Skip to content

Fix ENSNode Schema migrations execution#1996

Open
tk-o wants to merge 5 commits intomainfrom
fix/ensnode-migrations-concurrent-runs
Open

Fix ENSNode Schema migrations execution#1996
tk-o wants to merge 5 commits intomainfrom
fix/ensnode-migrations-concurrent-runs

Conversation

@tk-o
Copy link
Copy Markdown
Member

@tk-o tk-o commented Apr 24, 2026

Use advisory locks mechanism provided by ENSDb to ensure that any pending ENSNode Schema migrations are executed exactly once, even if multiple ENSIndexer instances attempt running migrations conurrently.

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • The migrateEnsNodeSchema method in EnsDbWriter class is now race-condition-safe.
    • The standard fix is a Postgres advisory lock — cheap, session-scoped, and automatically released on disconnect

Why

I noticed that the ENSDb instance in one of hosted ENSNode environments has five records in ensnode.__drizzle_migrations table with the same hash column value. It means that each of the five ENSIndexer instances in this ENSNode environment has executed the same pending migration file on the same ENSNode Schema.
image

To prevent any issues with running ENSNode Schema migrations by multiple ENSIndexer instances, we need to apply a locking mechanism so that only one ENSIndexer instance can attempt executing the pending migrations for the ENSNode Schema at a time.


Testing

  • I ran multiple ENSIndexer instances locally at the same time and noticed only one record was added into the ensnode.__drizzle_migrations table for one pending migration file. The lock works 👍

Notes for Reviewer (Optional)

  • Anything non-obvious or worth a heads-up.

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

Use advisory locks mechanism provided by ENSDb to ensure that any pending ENSNode Schema migrations are executed exactly once, even if multiple ENSIndexer instances attempt running migrations conurrently.
@tk-o tk-o requested a review from a team as a code owner April 24, 2026 16:40
Copilot AI review requested due to automatic review settings April 24, 2026 16:40
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment Apr 24, 2026 5:15pm
ensnode.io Ready Ready Preview, Comment Apr 24, 2026 5:15pm
ensrainbow.io Ready Ready Preview, Comment Apr 24, 2026 5:15pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 24, 2026

🦋 Changeset detected

Latest commit: 6b8c334

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@ensnode/ensdb-sdk Patch
ensapi Patch
ensindexer Patch
@ensnode/integration-test-env Patch
ensadmin Patch
ensrainbow Patch
fallback-ensapi Patch
enssdk Patch
enscli Patch
enskit Patch
ensskills Patch
@ensnode/datasources Patch
@ensnode/ensrainbow-sdk Patch
@ensnode/ensnode-react Patch
@ensnode/ensnode-sdk Patch
@ensnode/ponder-sdk Patch
@ensnode/ponder-subgraph Patch
@ensnode/shared-configs Patch
@docs/ensnode Patch
@docs/ensrainbow Patch
@namehash/ens-referrals Patch
@namehash/namehash-ui Patch
@ensnode/enskit-react-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

Warning

Rate limit exceeded

@tk-o has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 26 minutes and 43 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 26 minutes and 43 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a2780758-f57e-4892-b30f-7f1ed693bf3c

📥 Commits

Reviewing files that changed from the base of the PR and between 0d8a4b4 and 6b8c334.

📒 Files selected for processing (5)
  • .changeset/tough-clubs-eat.md
  • packages/ensdb-sdk/src/client/ensdb-writer.test.ts
  • packages/ensdb-sdk/src/client/ensdb-writer.ts
  • packages/ensdb-sdk/src/lib/advisory-lock-id.test.ts
  • packages/ensdb-sdk/src/lib/advisory-lock-id.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ensnode-migrations-concurrent-runs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to make ENSNode schema migrations execute exactly once when multiple ENSIndexer instances start concurrently, by introducing a PostgreSQL advisory-lock based synchronization mechanism in the ENSDb writer layer.

Changes:

  • Added advisoryLockId() helper to derive a stable bigint advisory lock ID from a string name.
  • Added unit tests for advisoryLockId() determinism and bigint-range behavior.
  • Updated EnsDbWriter.migrateEnsNodeSchema() to acquire/release a Postgres advisory lock around Drizzle migrations.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
packages/ensdb-sdk/src/lib/advisory-lock-id.ts Adds stable hashing helper to produce a Postgres advisory lock key.
packages/ensdb-sdk/src/lib/advisory-lock-id.test.ts Adds deterministic/unit-range tests for the lock key derivation.
packages/ensdb-sdk/src/client/ensdb-writer.ts Wraps ENSNode schema migrations with advisory lock acquisition/release.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/ensdb-sdk/src/client/ensdb-writer.ts Outdated
Comment thread packages/ensdb-sdk/src/client/ensdb-writer.ts Outdated
Comment thread packages/ensdb-sdk/src/client/ensdb-writer.ts Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 24, 2026

Greptile Summary

This PR fixes a race condition in EnsDbWriter.migrateEnsNodeSchema where multiple concurrent ENSIndexer instances could each execute the same pending migration, leading to duplicate records in ensnode.__drizzle_migrations. The fix wraps the migration in a Drizzle transaction and acquires a pg_advisory_xact_lock before running migrations — addressing both the connection-pool lock-pinning issue and the need for an explicit unlock that were raised in earlier review rounds.

Confidence Score: 5/5

Safe to merge — both previous P1 findings are fully addressed and the implementation is correct

The PR correctly uses pg_advisory_xact_lock inside a Drizzle transaction, which pins a single physical connection for the duration of the migration, automatically releases the lock on commit/rollback, and requires no explicit unlock. The advisoryLockId helper is deterministic and correctly bounded to the PostgreSQL bigint range. Tests cover the transaction contract, the lock SQL shape, and error propagation. No new P0 or P1 issues found.

No files require special attention

Important Files Changed

Filename Overview
packages/ensdb-sdk/src/client/ensdb-writer.ts Wraps migration in a Drizzle transaction with pg_advisory_xact_lock — correctly pins the connection, acquires the lock, runs migrations, and releases the lock automatically on transaction end
packages/ensdb-sdk/src/lib/advisory-lock-id.ts New utility that derives a stable signed 64-bit lock ID via SHA-256 of a string — deterministic, collision-resistant, and correctly bounded to the PostgreSQL bigint range
packages/ensdb-sdk/src/client/ensdb-writer.test.ts Tests updated to assert the transaction wrapper, advisory lock SQL shape, and that migrate receives the transaction object with correct migration config
packages/ensdb-sdk/src/lib/advisory-lock-id.test.ts New unit tests covering type, determinism, collision avoidance, a known hash fixture, and PostgreSQL bigint range bounds
.changeset/tough-clubs-eat.md Patch-level changeset entry for the @ensnode/ensdb-sdk package — correctly categorized

Sequence Diagram

sequenceDiagram
    participant I1 as ENSIndexer Instance 1
    participant I2 as ENSIndexer Instance 2
    participant PG as PostgreSQL

    I1->>PG: BEGIN TRANSACTION
    I1->>PG: SELECT pg_advisory_xact_lock(lockId)
    note right of PG: Lock acquired by I1

    I2->>PG: BEGIN TRANSACTION
    I2->>PG: SELECT pg_advisory_xact_lock(lockId)
    note right of PG: I2 blocks — waiting for lock

    I1->>PG: migrate(tx, {migrationsSchema: 'ensnode'})
    PG-->>I1: migrations applied

    I1->>PG: COMMIT (lock auto-released)
    note right of PG: I2 unblocks, acquires lock

    I2->>PG: migrate(tx, {migrationsSchema: 'ensnode'})
    note right of PG: No-op — migrations already applied
    I2->>PG: COMMIT (lock auto-released)
Loading

Reviews (3): Last reviewed commit: "Apply AI PR feedback" | Re-trigger Greptile

Comment thread packages/ensdb-sdk/src/client/ensdb-writer.ts Outdated
Comment thread packages/ensdb-sdk/src/client/ensdb-writer.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 24, 2026 17:04 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 24, 2026 17:04 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensnode.io April 24, 2026 17:04 Inactive
Copilot AI review requested due to automatic review settings April 24, 2026 17:05
@vercel vercel Bot temporarily deployed to Preview – ensnode.io April 24, 2026 17:05 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 24, 2026 17:05 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 24, 2026 17:05 Inactive
@tk-o tk-o force-pushed the fix/ensnode-migrations-concurrent-runs branch from 3586177 to 7358cc0 Compare April 24, 2026 17:07
@vercel vercel Bot temporarily deployed to Preview – ensnode.io April 24, 2026 17:07 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 24, 2026 17:07 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 24, 2026 17:07 Inactive
@tk-o
Copy link
Copy Markdown
Member Author

tk-o commented Apr 24, 2026

@greptile review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/ensdb-sdk/src/client/ensdb-writer.ts Outdated
Comment thread packages/ensdb-sdk/src/client/ensdb-writer.test.ts
Comment thread .changeset/tough-clubs-eat.md Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants