Temporal Workers
@cona/temporal-workers — the Node process that polls Temporal task queues and executes
activities. Runs on Fly.io in fra.
For queue routing and the workflows themselves see
Temporal Orchestration; for VM sizing see
Deployment Topology.
Bootstrap order
Startup order matters here: environment validation happens before any connection is opened, and worker-group selection happens before module load so Prisma pools size correctly.worker-group.ts is deliberately eight lines with a comment explaining why: worker
dependencies initialise Prisma pools at module load, so WORKER_GROUP must be set before
worker.js is imported, not inside run().
Worker factories
workers/index.ts:39-59 declares 19 production factories, each tagged with a group.
getWorkerFactories() filters by WORKER_GROUP (all starts everything) and appends
the test-document factory only when NODE_ENV !== "production".
Three factories produce more than one worker: shopify (parent + child), amazon
(settlements + VAT report), accounting and reconciliation (two lanes each), and
mirakl (one template × 6 marketplaces).
Health and shutdown
The health server is an internal Fly Machine check on:8080/health — workers expose
no public port and sit behind no proxy.
Shutdown is ordered deliberately (worker.ts:261-293):
- On
SIGTERM, close the health server first so Fly stops routing before workers drain. - Call
worker.run()shutdown; promises resolve when each worker reachesSTOPPED. Promise.allSettled, notPromise.all— the comment atworker.ts:277explains thatallshort-circuits on first rejection and would lose the per-worker failure log.- Flush telemetry. OTLP export is best-effort; the telemetry package absorbs exporter
failures so observability can never block shutdown (
worker.ts:377-378).
kill_timeout at 300s. The worker force deadline is 4m30s, leaving 30s for
connection, logger, and telemetry cleanup.
Source layout
Dependencies
Only 2 direct
@cona/core imports — business logic is reached through activities in
@cona/temporal-workflows, which imports core 292 times. The layering holds.
Notes
The accounting queue gets special treatment.ensureAccountingQueueRunning
(worker.ts:62) runs after worker creation to guarantee the long-lived
syncAccountingQueueWorkflow is active. See
Accounting Engine.
Workflow bundles are cached. create-worker.ts exposes
getWorkflowBundleCacheStats() and buildWorkflowBundle(); bundling all workflows per
worker would otherwise dominate startup.
No Sentry. Workers report to Axiom and OpenTelemetry only.