From 409e07cb49ef0e7a68d8f28b5a57a4a5d96110f4 Mon Sep 17 00:00:00 2001 From: shrugs Date: Fri, 3 Apr 2026 11:12:20 -0500 Subject: [PATCH 1/4] checkpoint: add otel tracing, remove subgraph_domains join in slow count query --- .../api/explore/registrar-actions-api.ts | 110 ++++++++------- .../find-registrar-actions.ts | 130 ++++++++++-------- 2 files changed, 132 insertions(+), 108 deletions(-) diff --git a/apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts b/apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts index 1e14060ab..89a0093a6 100644 --- a/apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts +++ b/apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts @@ -1,3 +1,5 @@ +import { trace } from "@opentelemetry/api"; + import { buildPageContext, type Node, @@ -10,6 +12,7 @@ import { } from "@ensnode/ensnode-sdk"; import { createApp } from "@/lib/hono-factory"; +import { withActiveSpanAsync } from "@/lib/instrumentation/auto-span"; import { makeLogger } from "@/lib/logger"; import { findRegistrarActions } from "@/lib/registrar-actions/find-registrar-actions"; import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware"; @@ -24,56 +27,69 @@ import { const app = createApp({ middlewares: [indexingStatusMiddleware, registrarActionsApiMiddleware] }); const logger = makeLogger("registrar-actions-api"); +const tracer = trace.getTracer("registrar-actions-api"); // Shared business logic for fetching registrar actions async function fetchRegistrarActions(parentNode: Node | undefined, query: RegistrarActionsQuery) { - const { - orderBy, - page, - recordsPerPage, - withReferral, - decodedReferrer, - beginTimestamp, - endTimestamp, - } = query; - - const filters: RegistrarActionsFilter[] = []; - - if (parentNode) { - filters.push(registrarActionsFilter.byParentNode(parentNode)); - } - - if (withReferral) { - filters.push(registrarActionsFilter.withReferral(true)); - } - - if (decodedReferrer) { - filters.push(registrarActionsFilter.byDecodedReferrer(decodedReferrer)); - } - - if (beginTimestamp) { - filters.push(registrarActionsFilter.beginTimestamp(beginTimestamp)); - } - - if (endTimestamp) { - filters.push(registrarActionsFilter.endTimestamp(endTimestamp)); - } - - // Calculate offset from page and recordsPerPage - const offset = (page - 1) * recordsPerPage; - - // Find the latest "logical registrar actions" with pagination - const { registrarActions, totalRecords } = await findRegistrarActions({ - filters, - orderBy, - limit: recordsPerPage, - offset, - }); - - // Build page context - const pageContext = buildPageContext(page, recordsPerPage, totalRecords); - - return { registrarActions, pageContext }; + return withActiveSpanAsync( + tracer, + "fetchRegistrarActions", + { + parentNode: parentNode ?? "undefined", + page: query.page, + recordsPerPage: query.recordsPerPage, + orderBy: query.orderBy, + }, + async () => { + const { + orderBy, + page, + recordsPerPage, + withReferral, + decodedReferrer, + beginTimestamp, + endTimestamp, + } = query; + + const filters: RegistrarActionsFilter[] = []; + + if (parentNode) { + filters.push(registrarActionsFilter.byParentNode(parentNode)); + } + + if (withReferral) { + filters.push(registrarActionsFilter.withReferral(true)); + } + + if (decodedReferrer) { + filters.push(registrarActionsFilter.byDecodedReferrer(decodedReferrer)); + } + + if (beginTimestamp) { + filters.push(registrarActionsFilter.beginTimestamp(beginTimestamp)); + } + + if (endTimestamp) { + filters.push(registrarActionsFilter.endTimestamp(endTimestamp)); + } + + // Calculate offset from page and recordsPerPage + const offset = (page - 1) * recordsPerPage; + + // Find the latest "logical registrar actions" with pagination + const { registrarActions, totalRecords } = await findRegistrarActions({ + filters, + orderBy, + limit: recordsPerPage, + offset, + }); + + // Build page context + const pageContext = buildPageContext(page, recordsPerPage, totalRecords); + + return { registrarActions, pageContext }; + }, + ); } /** diff --git a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts index faee5c0ec..70117aa65 100644 --- a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts +++ b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts @@ -1,3 +1,4 @@ +import { trace } from "@opentelemetry/api"; import { and, count, desc, eq, gte, isNotNull, lte, not, type SQL } from "drizzle-orm/sql"; import { @@ -21,6 +22,9 @@ import { } from "@ensnode/ensnode-sdk"; import { ensDb, ensIndexerSchema } from "@/lib/ensdb/singleton"; +import { withSpanAsync } from "@/lib/instrumentation/auto-span"; + +const tracer = trace.getTracer("registrar-actions"); /** * Build SQL for order clause from provided order param. @@ -97,33 +101,30 @@ interface FindRegistrarActionsOptions { export async function _countRegistrarActions( filters: RegistrarActionsFilter[] | undefined, ): Promise { - const countQuery = ensDb - .select({ - count: count(), - }) - .from(ensIndexerSchema.registrarActions) - // join Registration Lifecycles associated with Registrar Actions - .innerJoin( - ensIndexerSchema.registrationLifecycles, - eq(ensIndexerSchema.registrarActions.node, ensIndexerSchema.registrationLifecycles.node), - ) - // join Domains associated with Registration Lifecycles - .innerJoin( - ensIndexerSchema.subgraph_domain, - eq(ensIndexerSchema.registrationLifecycles.node, ensIndexerSchema.subgraph_domain.id), - ) - // join Subregistries associated with Registration Lifecycles - .innerJoin( - ensIndexerSchema.subregistries, - eq( - ensIndexerSchema.registrationLifecycles.subregistryId, - ensIndexerSchema.subregistries.subregistryId, - ), - ) - .where(and(...buildWhereClause(filters))); - - const result = await countQuery; - return result[0].count; + return withSpanAsync( + tracer, + "registrarActions.count", + { filterCount: filters?.length ?? 0 }, + async () => { + const result = await ensDb + .select({ count: count() }) + .from(ensIndexerSchema.registrarActions) + .innerJoin( + ensIndexerSchema.registrationLifecycles, + eq(ensIndexerSchema.registrarActions.node, ensIndexerSchema.registrationLifecycles.node), + ) + .innerJoin( + ensIndexerSchema.subregistries, + eq( + ensIndexerSchema.registrationLifecycles.subregistryId, + ensIndexerSchema.subregistries.subregistryId, + ), + ) + .where(and(...buildWhereClause(filters))); + + return result[0].count; + }, + ); } /** @@ -131,40 +132,47 @@ export async function _countRegistrarActions( * build a list of {@link NamedRegistrarAction} objects. */ export async function _findRegistrarActions(options: FindRegistrarActionsOptions) { - const query = ensDb - .select({ - registrarActions: ensIndexerSchema.registrarActions, - registrationLifecycles: ensIndexerSchema.registrationLifecycles, - subregistries: ensIndexerSchema.subregistries, - domain: ensIndexerSchema.subgraph_domain, - }) - .from(ensIndexerSchema.registrarActions) - // join Registration Lifecycles associated with Registrar Actions - .innerJoin( - ensIndexerSchema.registrationLifecycles, - eq(ensIndexerSchema.registrarActions.node, ensIndexerSchema.registrationLifecycles.node), - ) - // join Domains associated with Registration Lifecycles - .innerJoin( - ensIndexerSchema.subgraph_domain, - eq(ensIndexerSchema.registrationLifecycles.node, ensIndexerSchema.subgraph_domain.id), - ) - // join Subregistries associated with Registration Lifecycles - .innerJoin( - ensIndexerSchema.subregistries, - eq( - ensIndexerSchema.registrationLifecycles.subregistryId, - ensIndexerSchema.subregistries.subregistryId, - ), - ) - .where(and(...buildWhereClause(options.filters))) - .orderBy(buildOrderByClause(options.orderBy)) - .limit(options.limit) - .offset(options.offset); - - const records = await query; - - return records; + return withSpanAsync( + tracer, + "registrarActions.find", + { + filterCount: options.filters?.length ?? 0, + orderBy: options.orderBy, + limit: options.limit, + offset: options.offset, + }, + () => + ensDb + .select({ + registrarActions: ensIndexerSchema.registrarActions, + registrationLifecycles: ensIndexerSchema.registrationLifecycles, + subregistries: ensIndexerSchema.subregistries, + domain: ensIndexerSchema.subgraph_domain, + }) + .from(ensIndexerSchema.registrarActions) + // join Registration Lifecycles associated with Registrar Actions + .innerJoin( + ensIndexerSchema.registrationLifecycles, + eq(ensIndexerSchema.registrarActions.node, ensIndexerSchema.registrationLifecycles.node), + ) + // join Domains associated with Registration Lifecycles + .innerJoin( + ensIndexerSchema.subgraph_domain, + eq(ensIndexerSchema.registrationLifecycles.node, ensIndexerSchema.subgraph_domain.id), + ) + // join Subregistries associated with Registration Lifecycles + .innerJoin( + ensIndexerSchema.subregistries, + eq( + ensIndexerSchema.registrationLifecycles.subregistryId, + ensIndexerSchema.subregistries.subregistryId, + ), + ) + .where(and(...buildWhereClause(options.filters))) + .orderBy(buildOrderByClause(options.orderBy)) + .limit(options.limit) + .offset(options.offset), + ); } type MapToNamedRegistrarActionArgs = Awaited>[0]; From 1c05d0de57cba58d8618455afaa5d8aaea2cb48d Mon Sep 17 00:00:00 2001 From: shrugs Date: Fri, 3 Apr 2026 11:20:26 -0500 Subject: [PATCH 2/4] fix: conditionally join subregistries as needed --- .../find-registrar-actions.ts | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts index 70117aa65..c76222862 100644 --- a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts +++ b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts @@ -106,22 +106,33 @@ export async function _countRegistrarActions( "registrarActions.count", { filterCount: filters?.length ?? 0 }, async () => { - const result = await ensDb + let query = ensDb .select({ count: count() }) .from(ensIndexerSchema.registrarActions) - .innerJoin( - ensIndexerSchema.registrationLifecycles, - eq(ensIndexerSchema.registrarActions.node, ensIndexerSchema.registrationLifecycles.node), - ) - .innerJoin( - ensIndexerSchema.subregistries, - eq( - ensIndexerSchema.registrationLifecycles.subregistryId, - ensIndexerSchema.subregistries.subregistryId, - ), - ) - .where(and(...buildWhereClause(filters))); + .$dynamic(); + + const needsSubregistryJoin = filters?.some( + (f) => f.filterType === RegistrarActionsFilterTypes.BySubregistryNode, + ); + if (needsSubregistryJoin) { + query = query + .innerJoin( + ensIndexerSchema.registrationLifecycles, + eq( + ensIndexerSchema.registrarActions.node, + ensIndexerSchema.registrationLifecycles.node, + ), + ) + .innerJoin( + ensIndexerSchema.subregistries, + eq( + ensIndexerSchema.registrationLifecycles.subregistryId, + ensIndexerSchema.subregistries.subregistryId, + ), + ); + } + const result = await query.where(and(...buildWhereClause(filters))); return result[0].count; }, ); From 3688f95549bd142b2b93c6a02f97b47c201dd014 Mon Sep 17 00:00:00 2001 From: shrugs Date: Fri, 3 Apr 2026 11:30:32 -0500 Subject: [PATCH 3/4] fix: actually keep the join for correctness --- .../find-registrar-actions.ts | 37 +++++++------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts index c76222862..70117aa65 100644 --- a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts +++ b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts @@ -106,33 +106,22 @@ export async function _countRegistrarActions( "registrarActions.count", { filterCount: filters?.length ?? 0 }, async () => { - let query = ensDb + const result = await ensDb .select({ count: count() }) .from(ensIndexerSchema.registrarActions) - .$dynamic(); - - const needsSubregistryJoin = filters?.some( - (f) => f.filterType === RegistrarActionsFilterTypes.BySubregistryNode, - ); - if (needsSubregistryJoin) { - query = query - .innerJoin( - ensIndexerSchema.registrationLifecycles, - eq( - ensIndexerSchema.registrarActions.node, - ensIndexerSchema.registrationLifecycles.node, - ), - ) - .innerJoin( - ensIndexerSchema.subregistries, - eq( - ensIndexerSchema.registrationLifecycles.subregistryId, - ensIndexerSchema.subregistries.subregistryId, - ), - ); - } + .innerJoin( + ensIndexerSchema.registrationLifecycles, + eq(ensIndexerSchema.registrarActions.node, ensIndexerSchema.registrationLifecycles.node), + ) + .innerJoin( + ensIndexerSchema.subregistries, + eq( + ensIndexerSchema.registrationLifecycles.subregistryId, + ensIndexerSchema.subregistries.subregistryId, + ), + ) + .where(and(...buildWhereClause(filters))); - const result = await query.where(and(...buildWhereClause(filters))); return result[0].count; }, ); From 9a5d016e2a98b4c3a180cd1c39146e210ee4eda1 Mon Sep 17 00:00:00 2001 From: shrugs Date: Fri, 3 Apr 2026 11:53:27 -0500 Subject: [PATCH 4/4] fix: improper invariant caught by bot --- apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts index 70117aa65..91bc5b402 100644 --- a/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts +++ b/apps/ensapi/src/lib/registrar-actions/find-registrar-actions.ts @@ -184,7 +184,7 @@ type MapToNamedRegistrarActionArgs = Awaited