fix(events): fan-out resolves against an empty sink registry - #490
Open
theRealBithive wants to merge 1 commit into
Open
fix(events): fan-out resolves against an empty sink registry#490theRealBithive wants to merge 1 commit into
theRealBithive wants to merge 1 commit into
Conversation
Every event published since the WO-18 cutover fanned out to nothing.
`resolveTargets` reads a module-level array that only `registerAllResolvers()`
fills. Its sole caller was `getHookTargets()` in targets.ts, whose last
production call site disappeared in that cutover — `process.ts` records the
removal ("the legacy direct getHookTargets + bulk-add path is deleted"), but
nothing took over the registration. The registry therefore stayed empty for the
whole process lifetime and `resolveTargets` returned `[]` for every event: the
row was stamped `published_at`, no hook job was enqueued, and no sink fired at
all — integrations, webhooks, notifications, AI, summary, workflows, app
webhooks and remote status push. Nothing logged, nothing errored.
Observed on a self-hosted instance: 14 `event-dispatch` jobs succeeded, zero
rows ever appeared in the `events` queue, every `post.created` row carried
`published_at`, and `kv_store` held no `hooks:integration-mappings` entry —
proving the integration resolver had never once run.
`runEventDispatch` now registers before it resolves. The import is static
rather than deferred: `jobs/__tests__/handler-imports.test.ts` forbids a
call-time `import()` in a handler module because it would load that graph
inside a per-pass workspace scope, and nothing in the resolver graph imports
back into this module, so the cycle targets.ts works around is its own.
`resolveTargets` also logs an error when the registry is empty. The defining
property of this outage was silence; an empty registry is never a valid state
in a running tier, and finding this took a day of reading `events`,
`job_queue`, `kv_store` and `hook_deliveries` by hand because no log pointed
anywhere.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Author
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.

Every event published since the WO-18 cutover fanned out to nothing.
resolveTargetsreads a module-level array that onlyregisterAllResolvers()fills. Its sole caller wasgetHookTargets()in targets.ts, whose last production call site disappeared in that cutover —process.tsrecords the removal ("the legacy direct getHookTargets + bulk-add path is deleted"), but nothing took over the registration. The registry therefore stayed empty for the whole process lifetime andresolveTargetsreturned[]for every event: the row was stampedpublished_at, no hook job was enqueued, and no sink fired at all — integrations, webhooks, notifications, AI, summary, workflows, app webhooks and remote status push. Nothing logged, nothing errored.Observed on a self-hosted instance: 14
event-dispatchjobs succeeded, zero rows ever appeared in theeventsqueue, everypost.createdrow carriedpublished_at, andkv_storeheld nohooks:integration-mappingsentry — proving the integration resolver had never once run.runEventDispatchnow registers before it resolves. The import is static rather than deferred:jobs/__tests__/handler-imports.test.tsforbids a call-timeimport()in a handler module because it would load that graph inside a per-pass workspace scope, and nothing in the resolver graph imports back into this module, so the cycle targets.ts works around is its own.resolveTargetsalso logs an error when the registry is empty. The defining property of this outage was silence; an empty registry is never a valid state in a running tier, and finding this took a day of readingevents,job_queue,kv_storeandhook_deliveriesby hand because no log pointed anywhere.