Repository navigation
feat(backend): verification worker queue, job transitions, retry/dead-letter and heartbeats (#693, #694, #695, #696) - #929
Merged
Tybravo merged 2 commits intoOct 23, 2026
Conversation
…ters and heartbeats (Tybravo#693, Tybravo#694, Tybravo#695, Tybravo#696) On main, jobs/verificationWorker.ts had been reduced to a placeholder (runCycle returned 2, processEvent only logged), so nothing drove verification requests through the pipeline. This restores the worker pipeline from 2998b4c and builds the four issues on it. Tybravo#696 job state transitions - each request's VerificationJob moves pending -> processing -> tee_verifying -> minting -> completed through verificationService (the state-machine service), persisting teeAttestationHash, teeSignature, codeMeasurementHash and stellarTransactionHash at the stage that produces them, and the minted certificateId on completion - keeps verifyManifestForJob / startManifestRehashWorker from main Tybravo#694 queue abstraction and concurrency - services/workerQueue.service.ts: WorkerQueue (claim / release / deadLetter) and MongoWorkerQueue over the existing atomic, lease-guarded claim, so any number of workers share one queue without double-claiming - VERIFICATION_WORKER_CONCURRENCY lanes per worker process Tybravo#693 retry and dead letters - transient failures are released with exponential back-off (retryDelayMs, capped at 15 minutes) - permanent failures, or transient ones on the last attempt, mark the linked job failed with the reason and move the request to the deadLetteredRequests collection (models/DeadLetteredRequest.model.ts) Tybravo#695 heartbeat, health and telemetry - workerHeartbeats documents (workerId, status, lastProcessedLedger, counters, last request duration) updated on an interval and per cycle - GET /api/v1/worker/health (200 while a worker is alive, 503 otherwise) - every request logs its processing duration Tests: re-enables mongodb-memory-server in the attestation + mint integration suite and adds a two-worker concurrency case, updates the worker unit suite for the queue contract, and adds queue (real MongoDB) and heartbeat/health suites. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@FavorMax Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Owner
|
Thank you for the tasks done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
All four issues target
backend/src/jobs/verificationWorker.ts. Onmainthat file is currently a placeholder:runCycle()returns2,processEvent()only logs, andisRetryableError()always returnsfalse. So nothing drives verification requests through the pipeline. A full worker existed until93d39ce("fix: resolve remaining TypeScript compilation errors…") replaced it.The issues depend on each other, so they're delivered together, in dependency order:
2998b4c, its last complete version. Every service it uses still exists onmainwith the same API.Related Issues
Changes
#696 Worker → VerificationJob state transitions
VerificationJobthroughverificationService, the existing state-machine service. The transitions arepending → processing → tee_verifying → minting → completed, plusfailed.teeAttestationHash,teeSignatureandcodeMeasurementHashon enteringtee_verifyingstellarTransactionHashon enteringmintingcertificateIdoncompleted(new)manifestHashandrequestId, so contract-event ingestion (advanceFromAttestationEvent/completeFromMintEvent) can match events back to them.main:verifyManifestForJobandstartManifestRehashWorker, the manifest re-hash check.#694 Queue abstraction and concurrent workers
services/workerQueue.service.tsdefines aWorkerQueuecontract with three operations:claim,releaseanddeadLetter.MongoWorkerQueueimplements it on top of the existing atomicfindOneAndUpdateclaim and its time-limited lease. Two workers can never hold the same request, a crashed worker's request is reclaimed when its lease expires, and every later write is checked against the lease.deps.queue).deps.eventsnow handles only progress writes.VERIFICATION_WORKER_CONCURRENCYsetting (default 1). Each cycle runs that many lanes in parallel, sharing the batch budget. Any number of worker processes can share one database.#693 Retry policy and dead letters
retryDelayMs(attempt, baseMs)doubles the delay on each attempt and caps it at 15 minutes.failedwith the reason, through the state machine;deadLetteredRequestscollection (models/DeadLetteredRequest.model.ts): event, job, CIDs, requester, attempts, reason, error code, whether the final error was retryable, the worker and a timestamp;failed.#695 Heartbeat, health and telemetry
workerHeartbeatscollection (models/WorkerHeartbeat.model.ts) with fieldsworkerId,status,startedAt,lastHeartbeatAt,lastProcessedLedger,processedCount,failedCountandlastProcessingMs.VERIFICATION_WORKER_HEARTBEAT_INTERVAL_MS(default 15 s), after each cycle, and on stop. A failed heartbeat write is logged, never fatal.GET /api/v1/worker/health(controllers/worker.controller.ts→services/workerHeartbeat.service.ts→WorkerHeartbeatmodel). A worker counts as alive while it reportsrunningand its last heartbeat is newer thanWORKER_HEARTBEAT_STALE_MS(default 60 s). The endpoint returns 200 while at least one worker is alive and 503 otherwise.durationMs), including attempts that end in a retry or a dead letter.Configuration
The new optional settings, all with defaults, are documented in
.env.example:VERIFICATION_WORKER_CONCURRENCYVERIFICATION_WORKER_HEARTBEAT_INTERVAL_MSWORKER_HEARTBEAT_STALE_MSNo new dependencies.
Tests
__tests__/verificationWorker.test.ts(the existing suite) now uses a mockedWorkerQueueand expectsdeadLetterwhere requests now fail permanently. Three fixtures were updated to match the restored behaviour:createJobnow receivesmanifestHashandrequestId, andtee_verifyingjobs carry thecodeMeasurementHashthe state machine requires. New cases cover concurrency lanes, the back-off curve, persisting the certificate ID, dead-letter ordering, SPV rejections not being dead-lettered, duration logging and heartbeats.services/__tests__/attestationMint.integration.test.ts(from [Backend] [Testing] Integration test attestation and mint flow with mocked RPC #725) can't run onmain, because itsMongoMemoryServersetup is commented out. This PR restores that setup and adds two things: a dead-letter assertion, and a case where two workers with 3 lanes each drain 12 requests against real MongoDB and mint each one exactly once.services/__tests__/workerQueue.service.test.ts(real MongoDB):releasemakes a request claimable again only from its retry time;__tests__/worker.health.test.ts(real MongoDB): heartbeat upserts, the alive/stale rules, andGET /api/v1/worker/healthreturning 200 or 503.Verification Results
Commands were run from
backend/. Jest was run withjest.config.tsminussetupFilesAfterEnv, because the setup file it names is missing onmain. The full-suite runs used dummy values for the required environment variables, becauseconfig/env.tscallsprocess.exitwhen they are missing.__tests__/verificationWorker.test.ts: 42 of 42 pass. Onmainit fails 24 of 30.services/__tests__/attestationMint.integration.test.ts: 11 of 11 pass. Onmainthe suite can't run.services/__tests__/workerQueue.service.test.ts: 8 of 8 pass.__tests__/worker.health.test.ts: 6 of 6 pass.mainat658d68d:main: 158 failed, 331 passedmainnow pass (24 in the worker suite, 10 in the integration suite). The remaining failures are the same pre-existing ones on both, including one inverificationRequestEvent.service.test.ts, which this PR doesn't touch.tsc/pnpm --filter @stellarproof/backend run build: fails onmainand on this branch, because of a syntax error inservices/kms.service.tsaround line 430. That's a broken merge of feat(backend): certificate analytics, revocation, SPV linkage, KMS re-encryption (#741, #742, #743, #746) #926 and feat(kms): key expiry, scheduled rotation, and master-key rewrap #927, which this PR doesn't touch. CI's "Build Backend" step will fail for the same reason;mainitself has been red sincea53f674.Acceptance Criteria
The acceptance criteria are the same for all four issues. I've ticked each one only where this PR provides evidence for it.
#693 Retry and dead-letter handling
retryDelayMs; release with back-off is tested)deadLetteredRequests; tested on real MongoDB and end to end)workerQueue/verificationService→DeadLetteredRequest/VerificationJob/VerificationRequestEventmodels.envcredentials and real-life data: not done (mongodb-memory-server)Closes #693and a summary#694 Queue abstraction and concurrent workers
WorkerQueue,MongoWorkerQueue)VERIFICATION_WORKER_CONCURRENCYlanes each; two-worker end-to-end test)workerQueueservice →VerificationRequestEventmodel.envcredentials and real-life data: not done (mongodb-memory-server)Closes #694and a summary#695 Heartbeat, health and telemetry
workerHeartbeats: workerId, status, lastProcessedLedger and counters)GET /api/v1/worker/health, 200 or 503)durationMson every finished attempt)worker.controller→workerHeartbeat.service→WorkerHeartbeatmodel.envcredentials and real-life data: not done (mongodb-memory-server)/api/v1/worker/healthCloses #695and a summary#696 Worker → VerificationJob state transitions
teeAttestationHash,teeSignature,codeMeasurementHash,stellarTransactionHash, pluscertificateId)verificationService.updateJobStatus; illegal transitions are rejected by the existingVALID_TRANSITIONS)verificationService→VerificationJobmodel.envcredentials and real-life data: not done (mongodb-memory-server)Closes #696and a summaryNotes
These are pre-existing problems on
mainthat this PR doesn't fix:services/kms.service.tshas a syntax error, sotscand the backend build fail.jest.config.tspoints at a setup file that doesn't exist.verificationRequestEvent.service.test.tsfails onmainand fails here too.