Skip to content

Fix/registrar actions slowness#1870

Open
shrugs wants to merge 4 commits intomainfrom
fix/registrar-actions-slowness
Open

Fix/registrar actions slowness#1870
shrugs wants to merge 4 commits intomainfrom
fix/registrar-actions-slowness

Conversation

@shrugs
Copy link
Copy Markdown
Collaborator

@shrugs shrugs commented Apr 3, 2026

  • hotfix for registrar actions being super slow in production due to full table scans & unnecessary join on the subgraph domain table
  • branches off of the 1.9-patches pr v1.9 patches #1854 that's currently running in production

@shrugs shrugs requested a review from a team as a code owner April 3, 2026 16:22
Copilot AI review requested due to automatic review settings April 3, 2026 16:22
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 3, 2026

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

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
admin.ensnode.io Skipped Skipped Apr 3, 2026 4:55pm
ensnode.io Skipped Skipped Apr 3, 2026 4:55pm
ensrainbow.io Skipped Skipped Apr 3, 2026 4:55pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 3, 2026

⚠️ No Changeset found

Latest commit: 9a5d016

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Warning

Rate limit exceeded

@shrugs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 27 minutes and 52 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 27 minutes and 52 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: 30284eb7-31c9-4ab2-8dde-3fb386b9dd27

📥 Commits

Reviewing files that changed from the base of the PR and between 3688f95 and 9a5d016.

📒 Files selected for processing (1)
  • apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts
📝 Walkthrough

Walkthrough

Added OpenTelemetry tracing to the registrar-actions API handler and the registrar-actions business layer. Introduced module-level tracers and wrapped key operations in named spans, attaching span attributes. Adjusted the count query by removing an inner join to the domain/subgraph table.

Changes

Cohort / File(s) Summary
API handler tracing
apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts
Wrapped fetchRegistrarActions invocation with withActiveSpanAsync, created a "fetchRegistrarActions" span, and set span attributes (parentNode, page, recordsPerPage, orderBy). Moved filter/pagination and result construction into the span callback.
Business logic tracing & query tweak
apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts
Added module tracer and wrapped _countRegistrarActions and _findRegistrarActions with span wrappers ("registrarActions.count", "registrarActions.find"), recording relevant attributes. Modified the count SQL to remove the innerJoin to the subgraph_domain (domain) table; query execution otherwise preserved.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant API as "API Handler\n(registrar-actions-api)"
  participant Tracer as "OpenTelemetry\nTracer"
  participant BL as "Business Logic\n(find-registrar-actions)"
  participant DB

  Client->>API: Request fetchRegistrarActions(params)
  API->>Tracer: withActiveSpanAsync("fetchRegistrarActions")
  Tracer->>API: span(active)
  API->>BL: call fetchRegistrarActions (within span)
  BL->>Tracer: withSpanAsync("registrarActions.count") / "registrarActions.find"
  Tracer->>BL: span(s) active
  BL->>DB: execute count/find SQL (without domain innerJoin for count)
  DB-->>BL: rows / count
  BL-->>API: registrarActions + pageContext
  API-->>Tracer: end span("fetchRegistrarActions")
  API-->>Client: response (registrarActions, pageContext)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Poem

🐰
Traces hop softly through spans and logs,
Spans cradle queries, not tangled in bogs.
Joins slimmed down, footprints now small,
Observability twitches at every call.
Hooray — the rabbit applauds this traceball!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description covers the main issue and context but lacks structured detail on testing, notes for reviewer, and the blocking pre-review checklist required by the template. Complete the template by adding Testing section, Notes for Reviewer (if applicable), and checking off the Pre-Review Checklist items to clarify testing approach and risk assessment.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix/registrar actions slowness' directly addresses the main change—resolving performance issues in registrar actions by removing unnecessary joins and fixing full table scans.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/registrar-actions-slowness

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.

eq(ensIndexerSchema.registrarActions.node, ensIndexerSchema.registrationLifecycles.node),
)
// join Domains associated with Registration Lifecycles
.innerJoin(
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

removes the unnecessary join on domains, not needed for count

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 3, 2026

Greptile Summary

This PR is a hotfix targeting two related production issues in the registrar actions API: (1) excessive query latency caused by an unnecessary INNER JOIN on the subgraph_domain table in the count query, and (2) missing observability. The fix removes the subgraph_domain join from _countRegistrarActions (which only needs to count rows, not hydrate domain names), and wraps both the API handler (fetchRegistrarActions) and internal database helpers (_countRegistrarActions, _findRegistrarActions) with OpenTelemetry span instrumentation.

Key changes:

  • _countRegistrarActions now joins only registrationLifecycles + subregistries (removes subgraph_domain), reducing the query from a 4-table join to a 3-table join.
  • _findRegistrarActions retains all 4-table joins to populate domain.name for _mapToNamedRegistrarAction.
  • fetchRegistrarActions in registrar-actions-api.ts is wrapped with withActiveSpanAsync, creating a root-level active span for each API invocation.
  • _countRegistrarActions and _findRegistrarActions are each wrapped with withSpanAsync, which uses tracer.startSpan() rather than tracer.startActiveSpan().

The performance motivation is clear and the structural change is minimal. The join asymmetry between count and find (count omits subgraph_domain INNER JOIN) is the intentional performance trade-off, but relies on referential integrity between registrationLifecycles/subregistries and subgraph_domain being maintained at the indexer layer. The tracing additions provide welcome visibility into query latency.

Confidence Score: 4/5

Safe to merge for the performance win, but count/find join asymmetry flagged in prior threads remains structurally present and unaddressed.

The core performance fix (removing the subgraph_domain INNER JOIN from the count query) is correct and addresses the stated production latency problem. The tracing additions are additive and do not change query behavior. However, _countRegistrarActions now joins three tables while _findRegistrarActions joins four — the count omits the subgraph_domain INNER JOIN that the find query uses to hydrate domain.name. Under normal data integrity this is fine, but if any registrationLifecycle/subregistries row lacks a corresponding subgraph_domain entry, totalRecords will exceed the actual rows returned, producing phantom pagination pages. This concern flagged in prior threads has not been structurally resolved in this revision, warranting a 4/5 rather than 5/5.

apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts — specifically the join difference between _countRegistrarActions and _findRegistrarActions.

Important Files Changed

Filename Overview
apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts Removes subgraph_domain INNER JOIN from count query for performance, introduces OTel spans; count/find join asymmetry remains unresolved (tracked in prior threads), and withSpanAsync uses startSpan rather than startActiveSpan.
apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts Wraps fetchRegistrarActions with withActiveSpanAsync for tracing; the change is straightforward and correct — logic is unchanged, only span instrumentation added.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Handler as registrar-actions-api.ts
    participant Fetcher as fetchRegistrarActions
    participant FA as findRegistrarActions
    participant Count as _countRegistrarActions
    participant Find as _findRegistrarActions
    participant DB as PostgreSQL

    Client->>Handler: GET /api/registrar-actions[/:parentNode]
    Handler->>Fetcher: fetchRegistrarActions(parentNode, query)
    Note over Fetcher: OTel active span: fetchRegistrarActions
    Fetcher->>FA: findRegistrarActions(options)
    FA->>Count: _countRegistrarActions(filters)
    Note over Count: OTel span: registrarActions.count
    Count->>DB: SELECT count(*) 3-table JOIN + WHERE
    DB-->>Count: count N
    Count-->>FA: N
    FA->>Find: _findRegistrarActions(options)
    Note over Find: OTel span: registrarActions.find
    Find->>DB: SELECT rows 4-table JOIN + WHERE + LIMIT/OFFSET
    DB-->>Find: rows[]
    Find-->>FA: rows[]
    FA-->>Fetcher: registrarActions + totalRecords
    Fetcher-->>Handler: registrarActions + pageContext
    Handler-->>Client: JSON response
Loading

Reviews (2): Last reviewed commit: "fix: actually keep the join for correctn..." | Re-trigger Greptile

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

Hotfix aimed at reducing production slowness in the Registrar Actions explore endpoints by cutting down expensive query patterns (notably unnecessary joins/full table scan behavior) and adding tracing around the critical paths to aid diagnosis.

Changes:

  • Optimized _countRegistrarActions to avoid joining extra tables unless a subregistry-node filter is present.
  • Added OpenTelemetry spans around registrar-actions DB queries and API fetch logic for better observability.

Reviewed changes

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

File Description
apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts Adds OTel spans and refactors the count query to conditionally join tables only when needed.
apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts Wraps shared fetch logic in an active OTel span and attaches request attributes.

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

@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io April 3, 2026 16:30 Inactive
@vercel vercel bot temporarily deployed to Preview – ensnode.io April 3, 2026 16:30 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io April 3, 2026 16:30 Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts`:
- Around line 25-27: The spans created in _countRegistrarActions and
_findRegistrarActions use withSpanAsync (which calls tracer.startSpan) causing
them to be siblings of the outer span; change those calls to withActiveSpanAsync
so the spans become children of the active parent span. Specifically, replace
withSpanAsync with withActiveSpanAsync around the registrarActions.count and
registrarActions.find calls in the _countRegistrarActions and
_findRegistrarActions functions (keeping the same span names and attributes) so
the tracing hierarchy is preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5c86489a-2bdb-42a7-b753-68ea4d564e19

📥 Commits

Reviewing files that changed from the base of the PR and between 065ecbe and 1c05d0d.

📒 Files selected for processing (2)
  • apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts
  • apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts

@shrugs
Copy link
Copy Markdown
Collaborator Author

shrugs commented Apr 3, 2026

@greptile re-review

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts`:
- Around line 104-123: The count query in _countRegistrarActions (the
withSpanAsync "registrarActions.count" block) is missing the same join to the
subgraph_domain table that _findRegistrarActions uses, causing mismatched
totals; update the count builder to include the same join(s) as the fetch
path—i.e., add the innerJoin to ensIndexerSchema.subgraph_domains (the same join
condition used in _findRegistrarActions between ensIndexerSchema.subregistries
and ensIndexerSchema.subgraph_domains) so the .select({ count: count()
}).from(...).innerJoin(...).innerJoin(...).innerJoin(...) chain mirrors
_findRegistrarActions exactly and uses the identical buildWhereClause(filters)
to compute totals that match returned rows.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0e868c11-e8f7-4884-9c7f-e7135210360a

📥 Commits

Reviewing files that changed from the base of the PR and between 1c05d0d and 3688f95.

📒 Files selected for processing (1)
  • apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts

Copy link
Copy Markdown
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

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

Additional Suggestion:

Logic error in domain name validation: if (!record.domain.name === null) always evaluates to false, preventing the validation from ever throwing an error when the domain name is null

Fix on Vercel

Copilot AI review requested due to automatic review settings April 3, 2026 16:55
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io April 3, 2026 16:55 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io April 3, 2026 16:55 Inactive
@vercel vercel bot temporarily deployed to Preview – ensnode.io April 3, 2026 16:55 Inactive
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 2 out of 2 changed files in this pull request and generated 2 comments.


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

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