diff --git a/backend/src/services/sse.service.ts b/backend/src/services/sse.service.ts index acf9c50b..2afe60f5 100644 --- a/backend/src/services/sse.service.ts +++ b/backend/src/services/sse.service.ts @@ -1,5 +1,6 @@ +import { randomUUID } from 'crypto'; import type { Response } from 'express'; -import logger from '../logger.js'; +import logger, { requestContext } from '../logger.js'; import { isRedisAvailable, getPublisher, getSubscriber } from '../lib/redis.js'; const HEARTBEAT_INTERVAL_MS = 30_000; @@ -34,6 +35,13 @@ export class SSEService { private perIpPeakConnections = 0; private perUserPeakConnections = 0; + /** + * Stable id attached to every log line emitted by the heartbeat + * setInterval callback, since it fires outside of any HTTP request and + * would otherwise have no requestContext (and thus no correlation id). + */ + private readonly heartbeatWorkerId = `sse-heartbeat:${randomUUID()}`; + private readonly maxConnections: number = (() => { const parsed = Number.parseInt(process.env.MAX_SSE_CONNECTIONS ?? '10000', 10); if (!Number.isFinite(parsed) || parsed <= 0) return 10000; @@ -251,7 +259,9 @@ export class SSEService { } this.heartbeatTimer = setInterval(() => { - this.sendHeartbeat(); + requestContext.run({ requestId: this.heartbeatWorkerId }, () => { + this.sendHeartbeat(); + }); }, HEARTBEAT_INTERVAL_MS); } diff --git a/backend/src/workers/soroban-event-worker.ts b/backend/src/workers/soroban-event-worker.ts index d72f10de..4abb54cc 100644 --- a/backend/src/workers/soroban-event-worker.ts +++ b/backend/src/workers/soroban-event-worker.ts @@ -1,8 +1,9 @@ +import { randomUUID } from "crypto"; import { rpc, xdr, StrKey } from "@stellar/stellar-sdk"; import { prisma } from "../lib/prisma.js"; import { INDEXER_STATE_ID, ensureIndexerState } from "../lib/indexer-state.js"; import { sseService } from "../services/sse.service.js"; -import logger from "../logger.js"; +import logger, { requestContext } from "../logger.js"; import { Prisma } from "../generated/prisma/index.js"; import "../lib/stream-id.js"; @@ -112,6 +113,13 @@ export class SorobanEventWorker { /** Recent attempt outcomes for sliding-window spike detection. */ private recentOutcomes: { ok: boolean; at: number }[] = []; + /** + * Stable id attached to every log line emitted by the background poll + * loop, since these callbacks fire outside of any HTTP request and would + * otherwise have no requestContext (and thus no correlation id) at all. + */ + private readonly workerId = `soroban-worker:${randomUUID()}`; + constructor() { const rpcUrl = process.env.SOROBAN_RPC_URL ?? "https://soroban-testnet.stellar.org";