{"_id":"@axiomify/jobs","_rev":"4-44fef61d50868ee480e4707f18c4d0c7","name":"@axiomify/jobs","dist-tags":{"latest":"7.1.0"},"versions":{"6.3.3":{"name":"@axiomify/jobs","version":"6.3.3","author":{"url":"https://github.com/OTopman","name":"Topman","email":"okunlolatopman14@gmail.com"},"license":"MIT","_id":"@axiomify/jobs@6.3.3","maintainers":[{"name":"topman","email":"okunlolatopman14@gmail.com"}],"homepage":"https://github.com/OTopman/axiomify/blob/main/docs/packages/jobs.md","bugs":{"url":"https://github.com/OTopman/axiomify/issues"},"dist":{"shasum":"7b1fd11191ada99fe3138f8992a8cf5b43ec976f","tarball":"https://registry.npmjs.org/@axiomify/jobs/-/jobs-6.3.3.tgz","fileCount":6,"integrity":"sha512-2XpWNnLrLc10VcjVYUcOrrlKu3rRkTxK6GgLUP4GlbzYyjzJkNnHbcWvVTQtyr2czgX34kUKZGbNIFkCdSQ9WQ==","signatures":[{"sig":"MEUCIHtmjvxXYH/3JDIR56rn9NsaAYCsSiaweZ1Q7MrfnH2uAiEAnOJx0uRYjVH3cfnXYaDaDajG4YyO3MjyEk05Sp1JbDA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":187047},"main":"dist/index.js","types":"dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"8c8172eaacdeb225342992693b806ab443b60d2b","scripts":{"build":"tsup"},"_npmUser":{"name":"topman","email":"okunlolatopman14@gmail.com"},"repository":{"url":"git+https://github.com/OTopman/axiomify.git","type":"git","directory":"packages/jobs"},"_npmVersion":"10.9.8","description":"Distributed Job Scheduler, Worker, and Saga Coordinator for Axiomify.","directories":{},"_nodeVersion":"22.22.3","dependencies":{"@opentelemetry/sdk-node":"0.219.0","@opentelemetry/exporter-trace-otlp-grpc":"0.219.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","typescript":"^6.0.2","@axiomify/core":"*"},"peerDependencies":{"@axiomify/core":"*"},"_npmOperationalInternal":{"tmp":"tmp/jobs_6.3.3_1781781542361_0.6960911928047504","host":"s3://npm-registry-packages-npm-production"}},"7.0.0":{"name":"@axiomify/jobs","version":"7.0.0","author":{"url":"https://github.com/OTopman","name":"Topman","email":"okunlolatopman14@gmail.com"},"license":"MIT","_id":"@axiomify/jobs@7.0.0","maintainers":[{"name":"topman","email":"okunlolatopman14@gmail.com"}],"homepage":"https://github.com/OTopman/axiomify/blob/main/docs/packages/jobs.md","bugs":{"url":"https://github.com/OTopman/axiomify/issues"},"dist":{"shasum":"08d24a748df2059929a5a83d43c2cde2b7130437","tarball":"https://registry.npmjs.org/@axiomify/jobs/-/jobs-7.0.0.tgz","fileCount":6,"integrity":"sha512-CI86Y1TO0WYCfAXKW50L2dMvS4aGSMYLo70vKDFxGncY5x9kjkh5DlCOd48OOPWii8o/gL0IBbSqldYz6gkHBA==","signatures":[{"sig":"MEQCHzkU0JY7ioyQ0noKHgJhSUwUxaqDxokzJ2pxYLrArp4CIQC6Zrs72YtOHyTm1OxA6YMgReKyhPCkMm+pPkHf/VJAwQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@axiomify%2fjobs@7.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":188182},"main":"dist/index.js","types":"dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"fbf6e60487a5232ad20e80cfd584db8cb33e96b4","scripts":{"build":"tsup"},"_npmUser":{"name":"topman","email":"okunlolatopman14@gmail.com"},"repository":{"url":"git+https://github.com/OTopman/axiomify.git","type":"git","directory":"packages/jobs"},"_npmVersion":"10.8.2","description":"Distributed Job Scheduler, Worker, and Saga Coordinator for Axiomify.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@opentelemetry/sdk-node":"0.219.0","@opentelemetry/exporter-trace-otlp-grpc":"0.219.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","typescript":"^6.0.2","@axiomify/core":"*"},"peerDependencies":{"@axiomify/core":"*"},"_npmOperationalInternal":{"tmp":"tmp/jobs_7.0.0_1782944857562_0.38851695210500936","host":"s3://npm-registry-packages-npm-production"}},"7.0.1":{"name":"@axiomify/jobs","version":"7.0.1","author":{"url":"https://github.com/OTopman","name":"Topman","email":"okunlolatopman14@gmail.com"},"license":"MIT","_id":"@axiomify/jobs@7.0.1","maintainers":[{"name":"topman","email":"okunlolatopman14@gmail.com"}],"homepage":"https://github.com/OTopman/axiomify/blob/main/docs/packages/jobs.md","bugs":{"url":"https://github.com/OTopman/axiomify/issues"},"dist":{"shasum":"0b8df613c7d1c134e8544c6a8f1ae350a76f00da","tarball":"https://registry.npmjs.org/@axiomify/jobs/-/jobs-7.0.1.tgz","fileCount":6,"integrity":"sha512-6lT6ganduqXgtFLDCltRiaQ7dm3xaIbmcxjbi68SvY6QuVAQZvl+UUAQ6vYJj/NTz+pHWXDlM+gbc9h1zct8dw==","signatures":[{"sig":"MEQCIA4OeSe1s7Dpl5VpWzmj4xxqlXRglfW9peiBS9EjsZ3BAiBM+IAK3sY0adbe9R1pGCT62LLcQq9mCahqwjebV2rt/Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@axiomify%2fjobs@7.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":188350},"main":"dist/index.js","types":"dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"86ca53ddf22675696310ae2706003c6cecd017bd","scripts":{"build":"tsup"},"_npmUser":{"name":"topman","email":"okunlolatopman14@gmail.com"},"repository":{"url":"git+https://github.com/OTopman/axiomify.git","type":"git","directory":"packages/jobs"},"_npmVersion":"10.8.2","description":"Distributed Job Scheduler, Worker, and Saga Coordinator for Axiomify.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@opentelemetry/sdk-node":"0.221.0","@opentelemetry/exporter-trace-otlp-grpc":"0.221.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","typescript":"^6.0.2","@axiomify/core":"*"},"peerDependencies":{"@axiomify/core":"*"},"_npmOperationalInternal":{"tmp":"tmp/jobs_7.0.1_1785366586989_0.4030868393996332","host":"s3://npm-registry-packages-npm-production"}},"7.1.0":{"name":"@axiomify/jobs","version":"7.1.0","description":"Distributed Job Scheduler, Worker, and Saga Coordinator for Axiomify.","main":"dist/index.js","types":"dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup","test":"vitest run tests --config ../../vitest.config.mts"},"peerDependencies":{"@axiomify/core":"^7.0.0"},"devDependencies":{"@axiomify/core":"^7.1.0","tsup":"^8.5.1","typescript":"^6.0.2"},"author":{"name":"Topman","email":"okunlolatopman14@gmail.com","url":"https://github.com/OTopman"},"license":"MIT","homepage":"https://github.com/OTopman/axiomify/blob/main/docs/packages/jobs.md","repository":{"type":"git","url":"git+https://github.com/OTopman/axiomify.git","directory":"packages/jobs"},"bugs":{"url":"https://github.com/OTopman/axiomify/issues"},"publishConfig":{"access":"public"},"engines":{"node":">=20.0.0"},"dependencies":{"@opentelemetry/exporter-trace-otlp-grpc":"0.221.0","@opentelemetry/sdk-node":"0.221.0"},"_id":"@axiomify/jobs@7.1.0","gitHead":"c286687588228a3ade79dbe9eae74915a3d5d794","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-MZTjr5q8hi0gXh+MRwQ1QbdqS9hdAO8EuU4FXel/bZ4MtUIw+SVRnfzUSlMSsOFoWUBXStquSVsK9Yp+YZbO5w==","shasum":"430b6e3251f87efe5617f86067579bc8e28678f4","tarball":"https://registry.npmjs.org/@axiomify/jobs/-/jobs-7.1.0.tgz","fileCount":6,"unpackedSize":189207,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@axiomify%2fjobs@7.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIA+fjSPYLfv+669E9BBPzBonfDx5z8+OQF+KXRXtRKfyAiBcNsXFFWHa11VP3zUthWpqAQR9BHqS0itII+ilOaZTqQ=="}]},"_npmUser":{"name":"topman","email":"okunlolatopman14@gmail.com"},"directories":{},"maintainers":[{"name":"topman","email":"okunlolatopman14@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jobs_7.1.0_1786729718945_0.8397643268531074"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-18T11:19:02.248Z","modified":"2026-08-14T17:48:39.421Z","6.3.3":"2026-06-18T11:19:02.503Z","7.0.0":"2026-07-01T22:27:37.711Z","7.0.1":"2026-07-29T23:09:47.149Z","7.1.0":"2026-08-14T17:48:39.100Z"},"bugs":{"url":"https://github.com/OTopman/axiomify/issues"},"author":{"name":"Topman","email":"okunlolatopman14@gmail.com","url":"https://github.com/OTopman"},"license":"MIT","homepage":"https://github.com/OTopman/axiomify/blob/main/docs/packages/jobs.md","repository":{"type":"git","url":"git+https://github.com/OTopman/axiomify.git","directory":"packages/jobs"},"description":"Distributed Job Scheduler, Worker, and Saga Coordinator for Axiomify.","maintainers":[{"name":"topman","email":"okunlolatopman14@gmail.com"}],"readme":"# @axiomify/jobs\n\nA resilient, type-safe distributed queue and workflow coordination engine for Axiomify, featuring concurrent workers, auto-retry delays, SQL/Memory storage backends, Saga transactional orchestrators, and native Studio dashboard metrics integration.\n\n---\n\n## Features\n\n- **Pluggable Storage Adapters**: Built-in support for `MemoryJobStorage`, `SQLJobStorage`, and `RedisJobStorage`. Easily extensible to custom databases or cloud queues.\n- **Concurrent Queue Workers**: Configurable max concurrency limits, lease lock timeouts, and polling loops.\n- **Resilient Auto-Retry Management**: Automatic retry loops with customized backoff delays. Captures and persists error details and stack traces for debugging.\n- **Dead Letter Queue (DLQ)**: Automatically routes permanently failed tasks exceeding attempts to a designated queue namespace for offline inspection.\n- **Distributed Cron Locking**: Coordinated scheduling via `acquireCronLock` locks (Redis `SET NX PX`), ensuring exactly one cluster worker fires cron intervals.\n- **Saga Transaction Coordinator**: Orchestrates multi-step distributed operations, executing compensating rollback tasks in reverse order if any step fails.\n- **Studio Dashboard Console**: Native metrics integration exposing active, pending, completed, and failed tasks, with detailed JSON payload inspection and stack trace logs view.\n\n---\n\n## Installation\n\n```bash\nnpm install @axiomify/jobs\n```\n\n_Note: `@axiomify/core` is required as a peer dependency._\n\n---\n\n## Usage\n\n### 1. Registering the Jobs Module\n\nRegister the jobs module in your Axiomify container, register handlers, then\nstart its processing loop explicitly. The module terminates the scheduler\ngracefully when the app closes. Explicit startup keeps build-only commands such\nas route inspection and OpenAPI generation from launching background workers.\n\n```typescript\nimport { Axiomify } from '@axiomify/core';\nimport { jobsModule } from '@axiomify/jobs';\n\nconst app = new Axiomify();\n\napp.use(\n  jobsModule({\n    queue: 'default',\n    storage: 'memory', // Use 'sql' for persistent environments\n    maxConcurrency: 5,\n    pollIntervalMs: 1000,\n  }),\n);\n\nconst jobs = app.resolve('jobs');\n// Register handlers before starting the worker loop.\njobs.start();\n```\n\n### 2. Registering and Enqueuing Tasks\n\nInject the `jobs` scheduler from the dependency container to register task handlers and enqueue background workloads.\n\n```typescript\nconst jobs = app.resolve('jobs');\n\n// Register a task worker handler\njobs.register(\n  'send-welcome-email',\n  async (payload: { email: string; name: string }) => {\n    console.log(`Sending email to ${payload.name}...`);\n    // Async mail operation\n  },\n);\n\n// Enqueue a background task\nawait jobs.enqueue(\n  'send-welcome-email',\n  {\n    email: 'user@example.com',\n    name: 'John Doe',\n  },\n  {\n    attempts: 3, // max attempts\n    priority: 10,\n  },\n);\n```\n\n### 3. Saga Distributed Workflows\n\nFor multi-step distributed operations that span multiple microservices or tables, use the `SagaCoordinator` to chain steps together. If any step fails, the coordinator enqueues compensation jobs in reverse order.\n\n```typescript\nimport { SagaCoordinator } from '@axiomify/jobs';\n\nconst saga = new SagaCoordinator(jobs);\n\n// Step 1: Reserve inventory\nsaga.addStep(\n  'reserve-inventory',\n  async (ctx) => {\n    // Inventory reservation logic\n    return { itemId: '123' };\n  },\n  async (ctx) => {\n    // Rollback compensation: release inventory\n    await jobs.enqueue('release-inventory', { itemId: '123' });\n  },\n);\n\n// Step 2: Capture payment (this might throw)\nsaga.addStep(\n  'charge-card',\n  async (ctx) => {\n    throw new Error('Insufficient funds');\n  },\n  async (ctx) => {\n    // Rollback compensation: refund charge\n    await jobs.enqueue('refund-card', { amount: 50 });\n  },\n);\n\n// Execute the saga flow\nconst outcome = await saga.execute({ userId: 'user_99' });\nconsole.log(outcome.success); // false\n// Compensation 'release-inventory' is automatically enqueued!\n```\n\n---\n\n## API Reference\n\n### `jobsModule(options: JobsModuleOptions)`\n\nAxiomify `AppModule` that:\n\n- Instantiates the queue storage engine (`'memory' | 'sql' | 'redis'`).\n- Configures `JobScheduler` workers and registers it as a `'jobs'` service in the container.\n- Binds shutdown hooks to close background loops gracefully.\n\nKey `options` options:\n\n- `queue`: Queue namespace target (defaults to `'default'`).\n- `storage`: Storage backend — `'memory'`, `'sql'`, or `'redis'` (default: `'memory'`).\n- `client`: Application storage client (Drizzle/Prisma/Redis) passed to the `'sql'` / `'redis'` backends.\n- `maxConcurrency`: Maximum background tasks processed in parallel (default: `5`).\n- `pollIntervalMs`: Interval to check for pending jobs (default: `100` ms).\n- `lockDurationMs`: Lease lock expiration time in ms (default: `30000` ms).\n- `jobTimeoutMs`: Maximum time a single job handler may run before timing out (default: `30000` ms).\n- `drainTimeoutMs`: Maximum time `stop()` waits for active workers to drain (default: `30000` ms).\n- `dlqQueue`: Queue to route permanently failed jobs to (default: `${queue}:dlq`).\n\n### `JobScheduler` Class\n\nExtends `EventEmitter`.\n\n#### `register<P = any>(name: string, handler: JobHandler<P>): this`\n\nRegisters a worker function to execute tasks under the specified name with typed payload `P`. Returns the scheduler instance to support method chaining.\n\n#### `enqueue<P = any>(name: string, payload: P, options?: EnqueueOptions): Promise<string>`\n\nQueues a task for background processing.\n\n- `options.attempts`: Maximum execution retries (default: 3).\n- `options.priority`: Task sorting order (higher numbers run first).\n- `options.delayMs`: Delay in milliseconds before executing the job.\n\n#### `schedule(pattern: string, name: string, payload?: any): void`\n\nRegisters a recurring task or cron schedule. The `pattern` can be a numeric string interval in seconds (e.g., `'60'`) or a standard 5-field cron expression (e.g., `*/5 * * * *`).\n\n#### `start(): void`\n\nStarts the worker polling loops.\n\n#### `stop(): Promise<void>`\n\nStops polling and waits for active jobs to finish executing.\n\n#### Lifecycle Events\n\n- `start`: Emitted when a job starts execution. Passes `(job: Job)`.\n- `completed`: Emitted when a job completes successfully. Passes `(job: Job)`.\n- `retry`: Emitted when a job fails and is rescheduled for retry. Passes `(job: Job, error: Error)`.\n- `failed`: Emitted when a job fails permanently. Passes `(job: Job, error: Error)`.\n- `dlq`: Emitted when a job is routed to the Dead Letter Queue. Passes `(job: Job, error: Error)`.\n\n### `SagaCoordinator` Class\n\n#### `new SagaCoordinator(scheduler: JobScheduler)`\n\nCreates a new coordinator instance.\n\n#### `addStep(name: string, run: (ctx) => Promise<any>, compensate: (ctx) => Promise<any>): this`\n\nAdds an action step and its matching compensation task to the workflow chain. The compensation is auto-registered as a `compensate:<name>` job handler on the scheduler. Returns the coordinator instance for chaining.\n\n#### `execute(initialContext: any): Promise<{ success: boolean; context: any; error?: string }>`\n\nExecutes the workflow forwards. If a step throws, enqueues compensation jobs for all preceding completed steps in reverse order and returns `{ success: false, context, error }`.\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}