What problem are you trying to solve?
eve does not serialize concurrent deliveries that target the same continuation token. The token is both the session resume address and an exclusive workflow hook. If two invocations race before either session is established, each tries to claim the same hook and one can fail with HookConflictError.
GitHub webhooks make this easy to hit. Creating a pull request with a label can deliver opened and labeled close together. If an application opts into both actions, the GitHub channel starts both dispatches independently with waitUntil. Both derive the same per-PR continuation token, then call send. The losing delivery is logged by sendGitHubTurn, while hook ownership rejects the conflicting run (source).
This race happens before there is a shared session. defineState cannot coordinate it because its state is scoped to one existing session. The current documentation therefore tells every channel or application to build an external per-session queue (docs).
Proposed solution
Provide framework-owned admission control for deliveries sharing a continuation token. The default policy should preserve accepted work rather than throwing or silently dropping it. A durable queue is the clearest contract, though an explicit configurable coalescing policy could also work for channels that want it.
Required behavior:
- Two verified deliveries for the same continuation token can arrive concurrently before the session exists without producing
HookConflictError for normal admission contention.
- The framework creates or resumes one session and handles accepted deliveries in a documented order.
- Coordination works across processes, regions, cold starts, and retries. An in-memory mutex is insufficient.
- A crash after admission does not lose the delivery, and retrying the same delivery does not execute it twice when the caller supplies a stable delivery id or idempotency key.
- The caller receives or can observe the disposition of every delivery: started, queued, coalesced, deduplicated, or rejected. Nothing disappears behind a swallowed log.
- Different continuation tokens remain independently concurrent.
- Authentication, channel state, message context, and attachment metadata stay attached to the correct queued delivery.
- Admission contention does not become
session.failed and does not post an unrecoverable error to the user.
- Tests race two GitHub webhook deliveries for one PR from a cold state and prove deterministic completion. Add a separate test showing two PRs still run concurrently.
Alternatives considered
- Use
defineState as a lock. There is no session-scoped state to share during the creation race.
- Require every application to provision Redis or another external queue. That can work, but it duplicates continuation-token ownership rules and retry semantics outside eve.
- Catch and ignore
HookConflictError. This avoids a crash by losing a valid delivery.
Related: #170 reported the same error class, but the author closed it after finding that their immediate reproduction came from a custom Telegram handler. The distributed creation race remains untracked.
What problem are you trying to solve?
eve does not serialize concurrent deliveries that target the same continuation token. The token is both the session resume address and an exclusive workflow hook. If two invocations race before either session is established, each tries to claim the same hook and one can fail with
HookConflictError.GitHub webhooks make this easy to hit. Creating a pull request with a label can deliver
openedandlabeledclose together. If an application opts into both actions, the GitHub channel starts both dispatches independently withwaitUntil. Both derive the same per-PR continuation token, then callsend. The losing delivery is logged bysendGitHubTurn, while hook ownership rejects the conflicting run (source).This race happens before there is a shared session.
defineStatecannot coordinate it because its state is scoped to one existing session. The current documentation therefore tells every channel or application to build an external per-session queue (docs).Proposed solution
Provide framework-owned admission control for deliveries sharing a continuation token. The default policy should preserve accepted work rather than throwing or silently dropping it. A durable queue is the clearest contract, though an explicit configurable coalescing policy could also work for channels that want it.
Required behavior:
HookConflictErrorfor normal admission contention.session.failedand does not post an unrecoverable error to the user.Alternatives considered
defineStateas a lock. There is no session-scoped state to share during the creation race.HookConflictError. This avoids a crash by losing a valid delivery.Related: #170 reported the same error class, but the author closed it after finding that their immediate reproduction came from a custom Telegram handler. The distributed creation race remains untracked.