6.3 KiB
Capability Spec Delta: queue-distribution-worker-thread (enterprise-queue-distribution)
Package: @suaveplan/queue-distribution-worker-thread
Status: PROPOSED
Every requirement below carries a
**Verified by:**line at authoring time. (Seeopenspec/AGENTS.mdSection 13.)
ADDED Requirements
Requirement: WorkerFactory-driven communicator covering Web-Worker and worker_threads
The package SHALL expose WorkerThreadCommunicator implementing WorkerCommunicator from @suaveplan/queue-distribution-http (re-exported WorkerCommunicator interface). The constructor SHALL accept an injectable WorkerFactory of shape () => { postMessage(msg, transfer?); addEventListener(kind, handler); terminate(); } so the same class works against globalThis.Worker (browser) and a thin worker_threads wrapper (Node/Bun) without importing platform APIs at module scope. The implementation SHALL maintain a Map<requestId, { resolve, reject, timeoutHandle }> of outstanding requests. Each outgoing message SHALL include an id (generated via injected IdGenerator), a kind: "task" | "status" | "health" | "ping", and a payload validated by Zod. Reply correlation SHALL match id; unknown id replies SHALL be logged and dropped. Reply payloads SHALL be Zod-validated against per-kind schemas; failures SHALL reject the in-flight request with QueueDistributionWorkerThreadError(WT.MESSAGE_MALFORMED). Each request SHALL be subject to a per-call timeout (default defaultTimeoutMs) honoured by the injected Clock; expiry SHALL reject with WT.REQUEST_TIMEOUT and remove the entry from the map.
Scenario: round-trip correlation
- WHEN
sendTask/checkStatus/checkHealth/pingare invoked concurrently and the underlying worker replies in arbitrary order - THEN each promise resolves with its own reply payload (matched by
id)
Scenario: malformed reply throws WT.MESSAGE_MALFORMED
- WHEN the underlying worker posts back
{ id: <known>, kind: "task", payload: { something: "bad" } }not conforming to the task-reply Zod schema - THEN the in-flight
sendTaskpromise rejects withQueueDistributionWorkerThreadError(WT.MESSAGE_MALFORMED)
Scenario: request timeout
- WHEN a
FakeClockis injected and the worker never replies withindefaultTimeoutMs - THEN after the clock advances past the deadline, the call rejects with
QueueDistributionWorkerThreadError(WT.REQUEST_TIMEOUT)AND the outstanding-request map no longer contains the entry
Verified by: src/communicator/worker-thread/worker-thread-communicator.test.ts::"correlates concurrent replies by id" AND src/communicator/worker-thread/worker-thread-communicator.test.ts::"rejects with WT.MESSAGE_MALFORMED when reply fails Zod validation" AND src/communicator/worker-thread/worker-thread-communicator.test.ts::"rejects with WT.REQUEST_TIMEOUT and clears the outstanding-request map"
Requirement: WorkerThreadWorker — AbstractWorker subclass dispatching to a backing worker
The package SHALL ship WorkerThreadWorker extending AbstractWorker from @suaveplan/queue-distribution. Constructor SHALL accept an injectable WorkerFactory and instantiate a fresh WorkerThreadCommunicator per worker, AND a single backing worker thread. doStart() SHALL register error / exit listeners on the backing worker — worker.exit events SHALL markUnhealthy("Worker exited") and flip status to OFFLINE; uncaught error events SHALL emit the WT.WORKER_CRASHED OTel counter. doStop(force) SHALL terminate() the backing worker, fail every outstanding request with WT.WORKER_TERMINATED, and clear the outstanding-request map. doExecuteTask SHALL delegate to communicator.sendTask(<no-endpoint>, task, input, signal). getCapabilities() SHALL return { isRemote: false, isThreaded: true }. getType() SHALL return "worker-thread".
Scenario: backing worker crash promotes to UNHEALTHY
- WHEN the backing worker emits an
errorevent - THEN the OTel
queue_dist_wt.worker.crashed_totalcounter increments and the worker is marked UNHEALTHY
Scenario: terminate fails outstanding requests with WT.WORKER_TERMINATED
- WHEN two
sendTaskcalls are in flight andworker.stop(true)is invoked - THEN both pending promises reject with
QueueDistributionWorkerThreadError(WT.WORKER_TERMINATED)ANDworker.status === OFFLINE
Verified by: src/worker/worker-thread/worker-thread-worker.test.ts::"backing worker crash flips status to UNHEALTHY and increments WT.WORKER_CRASHED counter" AND src/worker/worker-thread/worker-thread-worker.test.ts::"terminate fails outstanding requests with WT.WORKER_TERMINATED"
Requirement: Stable error registry for the worker-thread plugin
The package SHALL register every error code through defineCodes("WT", [...]) from @suaveplan/error and expose QueueDistributionWorkerThreadError extends SuaveplanError<WtErrorCode>. The exhaustive set is: WORKER_CRASHED, MESSAGE_MALFORMED, REQUEST_TIMEOUT, WORKER_TERMINATED. Every code SHALL be thrown by ≥1 production call path.
Scenario: every registered code is thrown
- WHEN the test suite iterates over every code in the registry
- THEN a corresponding production throw site exists
Verified by: src/errors/queue-distribution-worker-thread-error.test.ts::"every registered WT.* code is thrown by a production call path"
Requirement: OpenTelemetry instrumentation
The package SHALL emit, via @suaveplan/opentelemetry under meter name "@suaveplan/queue-distribution-worker-thread":
- histogram:
queue_dist_wt.request.duration_ms(attributeskind,outcome) - counter:
queue_dist_wt.request_total(attributeskind,outcome) - counter:
queue_dist_wt.worker.crashed_total - counter:
queue_dist_wt.worker.terminated_total - span:
queue_dist_wt.sendTask
Scenario: histogram emission on sendTask round-trip
- WHEN
sendTaskresolves successfully under an in-memoryMeterProvider - THEN one observation is recorded on
queue_dist_wt.request.duration_mswithkind === "task"ANDoutcome === "success"
Verified by: src/communicator/worker-thread/worker-thread-communicator.spec-conformance.test.ts::"emits queue_dist_wt.request.duration_ms histogram with kind and outcome attributes"