@igniter-js/jobs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +557 -0
- package/README.md +410 -0
- package/dist/adapter-CcQCatSa.d.mts +1411 -0
- package/dist/adapter-CcQCatSa.d.ts +1411 -0
- package/dist/adapters/bullmq.adapter.d.mts +131 -0
- package/dist/adapters/bullmq.adapter.d.ts +131 -0
- package/dist/adapters/bullmq.adapter.js +598 -0
- package/dist/adapters/bullmq.adapter.js.map +1 -0
- package/dist/adapters/bullmq.adapter.mjs +596 -0
- package/dist/adapters/bullmq.adapter.mjs.map +1 -0
- package/dist/adapters/index.d.mts +5 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.js +1129 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/index.mjs +1126 -0
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/adapters/memory.adapter.d.mts +118 -0
- package/dist/adapters/memory.adapter.d.ts +118 -0
- package/dist/adapters/memory.adapter.js +571 -0
- package/dist/adapters/memory.adapter.js.map +1 -0
- package/dist/adapters/memory.adapter.mjs +569 -0
- package/dist/adapters/memory.adapter.mjs.map +1 -0
- package/dist/index.d.mts +1107 -0
- package/dist/index.d.ts +1107 -0
- package/dist/index.js +1137 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1128 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +93 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
# @igniter-js/jobs - Agent Manual
|
|
2
|
+
|
|
3
|
+
> **Last Updated:** 2025-01-01
|
|
4
|
+
> **Version:** 0.1.0
|
|
5
|
+
|
|
6
|
+
## 1. Package Overview
|
|
7
|
+
|
|
8
|
+
### Purpose
|
|
9
|
+
|
|
10
|
+
`@igniter-js/jobs` provides type-safe background job processing for TypeScript applications, powered by BullMQ and Redis. It follows the Igniter Builder API pattern for maximum type safety and developer experience.
|
|
11
|
+
|
|
12
|
+
### Core Concepts
|
|
13
|
+
|
|
14
|
+
| Concept | Description |
|
|
15
|
+
|---------|-------------|
|
|
16
|
+
| **Queue** | Named container for jobs (e.g., `email`, `notifications`) |
|
|
17
|
+
| **Job** | Unit of work with typed payload and handler |
|
|
18
|
+
| **Cron Job** | Scheduled job with pattern or interval |
|
|
19
|
+
| **Worker** | Process that executes jobs from queues |
|
|
20
|
+
| **Scope** | Multi-tenant context (e.g., organization, workspace) |
|
|
21
|
+
| **Actor** | Entity that triggered the job (e.g., user, system) |
|
|
22
|
+
| **Adapter** | Implementation for queue backend (BullMQ, Memory) |
|
|
23
|
+
|
|
24
|
+
### Package Exports
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// Main entry point
|
|
28
|
+
import { IgniterJobs, IgniterQueue, IgniterJobsError } from '@igniter-js/jobs'
|
|
29
|
+
|
|
30
|
+
// Adapters
|
|
31
|
+
import { BullMQAdapter, MemoryAdapter } from '@igniter-js/jobs/adapters'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 2. Architecture
|
|
37
|
+
|
|
38
|
+
### File Structure
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
packages/jobs/
|
|
42
|
+
├── src/
|
|
43
|
+
│ ├── index.ts # Main exports
|
|
44
|
+
│ ├── types/
|
|
45
|
+
│ │ ├── index.ts # Type exports
|
|
46
|
+
│ │ ├── scope.ts # Scope/Actor types
|
|
47
|
+
│ │ ├── job.ts # Job definition types
|
|
48
|
+
│ │ ├── queue.ts # Queue config types
|
|
49
|
+
│ │ ├── events.ts # Event types
|
|
50
|
+
│ │ ├── adapter.ts # Adapter interface
|
|
51
|
+
│ │ ├── config.ts # Builder state types
|
|
52
|
+
│ │ └── worker.ts # Worker types
|
|
53
|
+
│ ├── errors/
|
|
54
|
+
│ │ ├── index.ts # Error exports
|
|
55
|
+
│ │ └── igniter-jobs.error.ts # Error class and codes
|
|
56
|
+
│ ├── builders/
|
|
57
|
+
│ │ ├── index.ts # Builder exports
|
|
58
|
+
│ │ ├── igniter-queue.builder.ts # Queue builder
|
|
59
|
+
│ │ ├── igniter-jobs.builder.ts # Jobs builder
|
|
60
|
+
│ │ └── igniter-worker.builder.ts # Worker builder
|
|
61
|
+
│ ├── core/
|
|
62
|
+
│ │ ├── index.ts # Core exports
|
|
63
|
+
│ │ └── igniter-jobs.ts # Runtime class
|
|
64
|
+
│ └── adapters/
|
|
65
|
+
│ ├── index.ts # Adapter exports
|
|
66
|
+
│ ├── bullmq.adapter.ts # BullMQ implementation
|
|
67
|
+
│ └── memory.adapter.ts # Memory implementation
|
|
68
|
+
├── tests/
|
|
69
|
+
│ ├── igniter-queue.builder.test.ts
|
|
70
|
+
│ ├── igniter-jobs.builder.test.ts
|
|
71
|
+
│ ├── igniter-jobs.runtime.test.ts
|
|
72
|
+
│ └── memory.adapter.test.ts
|
|
73
|
+
├── package.json
|
|
74
|
+
├── tsconfig.json
|
|
75
|
+
├── tsup.config.ts
|
|
76
|
+
├── vitest.config.ts
|
|
77
|
+
├── README.md
|
|
78
|
+
└── AGENTS.md # This file
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Builder Pattern Flow
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
1. IgniterQueue.create('name')
|
|
85
|
+
└─► addJob() / addCron()
|
|
86
|
+
└─► build() → IgniterQueueBuiltConfig
|
|
87
|
+
|
|
88
|
+
2. IgniterJobs.create()
|
|
89
|
+
└─► withAdapter()
|
|
90
|
+
└─► addQueue()
|
|
91
|
+
└─► addScope() / addActor()
|
|
92
|
+
└─► withDefaults()
|
|
93
|
+
└─► build() → IgniterJobsRuntime (with Proxy)
|
|
94
|
+
|
|
95
|
+
3. jobs.queueName.jobName.dispatch(data)
|
|
96
|
+
└─► Proxy intercepts access
|
|
97
|
+
└─► Returns typed dispatch function
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Proxy-Based API
|
|
101
|
+
|
|
102
|
+
The runtime uses JavaScript Proxy to provide type-safe access:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// How it works internally:
|
|
106
|
+
jobs.email.sendWelcome.dispatch(data)
|
|
107
|
+
│ │ │
|
|
108
|
+
│ │ └── Job proxy with dispatch/schedule methods
|
|
109
|
+
│ └── Queue proxy returning job proxies
|
|
110
|
+
└── Root proxy returning queue proxies
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 3. Key Components
|
|
116
|
+
|
|
117
|
+
### 3.1 IgniterQueue Builder
|
|
118
|
+
|
|
119
|
+
**Location:** `src/builders/igniter-queue.builder.ts`
|
|
120
|
+
|
|
121
|
+
**Purpose:** Define queue configuration with type-safe job definitions.
|
|
122
|
+
|
|
123
|
+
**Key Methods:**
|
|
124
|
+
- `create(name, options?)` - Initialize builder
|
|
125
|
+
- `addJob(name, config)` - Add job with schema and handler
|
|
126
|
+
- `addCron(name, config)` - Add cron job
|
|
127
|
+
- `build()` - Return frozen config
|
|
128
|
+
|
|
129
|
+
**Type Flow:**
|
|
130
|
+
```typescript
|
|
131
|
+
IgniterQueue.create('email')
|
|
132
|
+
.addJob('send', { schema, handler })
|
|
133
|
+
// Jobs type accumulates: { send: {...} }
|
|
134
|
+
.build()
|
|
135
|
+
// Returns: IgniterQueueBuiltConfig<'email', Jobs>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 3.2 IgniterJobs Builder
|
|
139
|
+
|
|
140
|
+
**Location:** `src/builders/igniter-jobs.builder.ts`
|
|
141
|
+
|
|
142
|
+
**Purpose:** Create jobs runtime with adapter, context, and queues.
|
|
143
|
+
|
|
144
|
+
**Key Methods:**
|
|
145
|
+
- `create<Context>()` - Initialize with context type
|
|
146
|
+
- `withAdapter(adapter)` - Set queue adapter (required)
|
|
147
|
+
- `withContext(factory)` - Set context factory for handlers
|
|
148
|
+
- `addQueue(queue)` - Add queue configuration
|
|
149
|
+
- `addScope(name, config)` - Define scope type
|
|
150
|
+
- `addActor(name, config)` - Define actor type
|
|
151
|
+
- `withTelemetry(adapter)` - Enable tracing
|
|
152
|
+
- `withDefaults(options)` - Default job options
|
|
153
|
+
- `build()` - Return runtime instance
|
|
154
|
+
|
|
155
|
+
### 3.3 IgniterJobs Runtime
|
|
156
|
+
|
|
157
|
+
**Location:** `src/core/igniter-jobs.ts`
|
|
158
|
+
|
|
159
|
+
**Purpose:** Main runtime class with proxy-based access.
|
|
160
|
+
|
|
161
|
+
**Key Properties:**
|
|
162
|
+
- `[queueName]` - Queue proxy (via Proxy)
|
|
163
|
+
- `job` - Job management methods
|
|
164
|
+
- `queue` - Queue management methods
|
|
165
|
+
- `subscribe` - Event subscription
|
|
166
|
+
- `search` - Search methods
|
|
167
|
+
- `worker` - Worker builder access
|
|
168
|
+
- `shutdown()` - Graceful shutdown
|
|
169
|
+
|
|
170
|
+
### 3.4 Adapters
|
|
171
|
+
|
|
172
|
+
**BullMQ Adapter:** `src/adapters/bullmq.adapter.ts`
|
|
173
|
+
- Production-ready with Redis
|
|
174
|
+
- Supports all BullMQ features
|
|
175
|
+
- Lazy loads BullMQ module
|
|
176
|
+
|
|
177
|
+
**Memory Adapter:** `src/adapters/memory.adapter.ts`
|
|
178
|
+
- For testing/development
|
|
179
|
+
- No external dependencies
|
|
180
|
+
- Simulates job processing
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 4. Type System
|
|
185
|
+
|
|
186
|
+
### Core Type Hierarchy
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// Job Definition (queue level)
|
|
190
|
+
interface IgniterJobDefinition<TData, TResult, TContext> {
|
|
191
|
+
schema: ZodSchema<TData>
|
|
192
|
+
handler: IgniterJobHandler<TData, TResult, TContext>
|
|
193
|
+
options?: IgniterJobOptions
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Handler Context (passed to handler)
|
|
197
|
+
interface IgniterJobHandlerContext<TData, TContext> {
|
|
198
|
+
data: TData
|
|
199
|
+
context: TContext
|
|
200
|
+
job: { id: string; name: string; queue: string; attempt: number }
|
|
201
|
+
log: (level, message) => Promise<void>
|
|
202
|
+
updateProgress: (progress) => Promise<void>
|
|
203
|
+
scope?: IgniterJobScopeEntry
|
|
204
|
+
actor?: IgniterJobActorEntry
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Dispatch Options
|
|
208
|
+
interface DispatchOptions {
|
|
209
|
+
delay?: number
|
|
210
|
+
priority?: number
|
|
211
|
+
attempts?: number
|
|
212
|
+
backoff?: IgniterJobBackoff
|
|
213
|
+
jobId?: string
|
|
214
|
+
scope?: { type: string; id: string }
|
|
215
|
+
actor?: { type: string; id: string }
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Type Inference Chain
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// 1. Define schema
|
|
223
|
+
const schema = z.object({ email: z.string() })
|
|
224
|
+
// Type: z.ZodObject<{ email: z.ZodString }>
|
|
225
|
+
|
|
226
|
+
// 2. Schema infers handler data type
|
|
227
|
+
handler: async ({ data }) => { ... }
|
|
228
|
+
// data type: { email: string }
|
|
229
|
+
|
|
230
|
+
// 3. Queue builder accumulates job types
|
|
231
|
+
.addJob('sendWelcome', { schema, handler })
|
|
232
|
+
// Jobs type: { sendWelcome: { data: { email: string } } }
|
|
233
|
+
|
|
234
|
+
// 4. Runtime proxy provides typed dispatch
|
|
235
|
+
jobs.email.sendWelcome.dispatch({ email: 'x' })
|
|
236
|
+
// Argument type: { email: string }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 5. Error Handling
|
|
242
|
+
|
|
243
|
+
### Error Codes
|
|
244
|
+
|
|
245
|
+
**Configuration Errors:**
|
|
246
|
+
- `JOBS_MISSING_ADAPTER` - No adapter provided
|
|
247
|
+
- `JOBS_INVALID_QUEUE_NAME` - Invalid queue name
|
|
248
|
+
- `JOBS_INVALID_JOB_NAME` - Invalid job name
|
|
249
|
+
- `JOBS_DUPLICATE_QUEUE` - Queue already registered
|
|
250
|
+
- `JOBS_DUPLICATE_JOB` - Job already registered
|
|
251
|
+
|
|
252
|
+
**Queue Errors:**
|
|
253
|
+
- `JOBS_QUEUE_NOT_FOUND` - Queue doesn't exist
|
|
254
|
+
- `JOBS_QUEUE_PAUSED` - Queue is paused
|
|
255
|
+
- `JOBS_QUEUE_FAILED_TO_PAUSE` - Pause operation failed
|
|
256
|
+
|
|
257
|
+
**Job Errors:**
|
|
258
|
+
- `JOBS_JOB_NOT_FOUND` - Job doesn't exist
|
|
259
|
+
- `JOBS_JOB_VALIDATION_FAILED` - Payload validation failed
|
|
260
|
+
- `JOBS_JOB_HANDLER_FAILED` - Handler threw error
|
|
261
|
+
- `JOBS_JOB_TIMEOUT` - Job exceeded timeout
|
|
262
|
+
|
|
263
|
+
**Dispatch Errors:**
|
|
264
|
+
- `JOBS_DISPATCH_FAILED` - Dispatch operation failed
|
|
265
|
+
- `JOBS_SCHEDULE_FAILED` - Schedule operation failed
|
|
266
|
+
- `JOBS_INVALID_DISPATCH_PAYLOAD` - Invalid payload
|
|
267
|
+
|
|
268
|
+
### Error Class
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
throw new IgniterJobsError({
|
|
272
|
+
code: 'JOBS_JOB_NOT_FOUND',
|
|
273
|
+
message: `Job "${jobId}" not found in queue "${queue}"`,
|
|
274
|
+
statusCode: 404,
|
|
275
|
+
details: { jobId, queue },
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## 6. Development Guidelines
|
|
282
|
+
|
|
283
|
+
### Adding New Features
|
|
284
|
+
|
|
285
|
+
1. **Add Types First**
|
|
286
|
+
- Define in appropriate `src/types/*.ts` file
|
|
287
|
+
- Export from `src/types/index.ts`
|
|
288
|
+
- Export from `src/index.ts` if public
|
|
289
|
+
|
|
290
|
+
2. **Update Builders**
|
|
291
|
+
- Add method to builder class
|
|
292
|
+
- Update state type if needed
|
|
293
|
+
- Maintain fluent return type
|
|
294
|
+
|
|
295
|
+
3. **Update Runtime**
|
|
296
|
+
- Implement in `src/core/igniter-jobs.ts`
|
|
297
|
+
- Add proxy handling if needed
|
|
298
|
+
|
|
299
|
+
4. **Update Adapter Interface**
|
|
300
|
+
- Add method to `IgniterJobsAdapter`
|
|
301
|
+
- Implement in BullMQ adapter
|
|
302
|
+
- Implement in Memory adapter
|
|
303
|
+
|
|
304
|
+
5. **Add Tests**
|
|
305
|
+
- Unit test for builder method
|
|
306
|
+
- Integration test for runtime
|
|
307
|
+
- Adapter test for implementation
|
|
308
|
+
|
|
309
|
+
### Testing Strategy
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
# Run all tests
|
|
313
|
+
npm test
|
|
314
|
+
|
|
315
|
+
# Watch mode
|
|
316
|
+
npm run test:watch
|
|
317
|
+
|
|
318
|
+
# Coverage
|
|
319
|
+
npm run test:coverage
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Test Files:**
|
|
323
|
+
- `tests/igniter-queue.builder.test.ts` - Queue builder
|
|
324
|
+
- `tests/igniter-jobs.builder.test.ts` - Jobs builder
|
|
325
|
+
- `tests/igniter-jobs.runtime.test.ts` - Integration
|
|
326
|
+
- `tests/memory.adapter.test.ts` - Memory adapter
|
|
327
|
+
|
|
328
|
+
### Code Style
|
|
329
|
+
|
|
330
|
+
- Use JSDoc for all public APIs
|
|
331
|
+
- Follow existing patterns exactly
|
|
332
|
+
- No `any` types in public API
|
|
333
|
+
- Export types explicitly
|
|
334
|
+
- Use `readonly` where appropriate
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 7. Adapter Implementation Guide
|
|
339
|
+
|
|
340
|
+
### Required Methods
|
|
341
|
+
|
|
342
|
+
When implementing a new adapter, implement ALL methods from `IgniterJobsAdapter`:
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
interface IgniterJobsAdapter {
|
|
346
|
+
// Connection
|
|
347
|
+
readonly client: unknown
|
|
348
|
+
|
|
349
|
+
// Job Operations
|
|
350
|
+
dispatch(params: AdapterDispatchParams): Promise<string>
|
|
351
|
+
schedule(params: AdapterScheduleParams): Promise<string>
|
|
352
|
+
getJob(queue: string, jobId: string): Promise<IgniterJobInfo | null>
|
|
353
|
+
getJobState(queue: string, jobId: string): Promise<IgniterJobStatus | null>
|
|
354
|
+
getJobProgress(queue: string, jobId: string): Promise<number>
|
|
355
|
+
getJobLogs(queue: string, jobId: string): Promise<IgniterJobLog[]>
|
|
356
|
+
retryJob(queue: string, jobId: string): Promise<void>
|
|
357
|
+
removeJob(queue: string, jobId: string): Promise<void>
|
|
358
|
+
promoteJob(queue: string, jobId: string): Promise<void>
|
|
359
|
+
moveJob(queue: string, jobId: string, state: string, reason?: string): Promise<void>
|
|
360
|
+
retryJobs(queue: string, jobIds: string[]): Promise<void>
|
|
361
|
+
removeJobs(queue: string, jobIds: string[]): Promise<void>
|
|
362
|
+
|
|
363
|
+
// Queue Operations
|
|
364
|
+
getQueue(queue: string): Promise<IgniterQueueInfo>
|
|
365
|
+
pauseQueue(queue: string): Promise<void>
|
|
366
|
+
resumeQueue(queue: string): Promise<void>
|
|
367
|
+
drainQueue(queue: string): Promise<number>
|
|
368
|
+
cleanQueue(queue: string, options: IgniterQueueCleanOptions): Promise<number>
|
|
369
|
+
obliterateQueue(queue: string, options?: { force?: boolean }): Promise<void>
|
|
370
|
+
retryAllFailed(queue: string): Promise<number>
|
|
371
|
+
getJobCounts(queue: string): Promise<IgniterJobCounts>
|
|
372
|
+
listJobs(queue: string, options?: {...}): Promise<IgniterJobSearchResult[]>
|
|
373
|
+
pauseJobType(queue: string, jobName: string): Promise<void>
|
|
374
|
+
resumeJobType(queue: string, jobName: string): Promise<void>
|
|
375
|
+
|
|
376
|
+
// Events
|
|
377
|
+
subscribe(pattern: string, handler: IgniterJobEventHandler): Promise<IgniterJobUnsubscribeFn>
|
|
378
|
+
|
|
379
|
+
// Workers
|
|
380
|
+
createWorker(config: AdapterWorkerConfig, handler: AdapterJobHandler): Promise<AdapterWorkerHandle>
|
|
381
|
+
|
|
382
|
+
// Search
|
|
383
|
+
searchJobs(filter: {...}): Promise<IgniterJobSearchResult[]>
|
|
384
|
+
searchQueues(filter: {...}): Promise<IgniterQueueInfo[]>
|
|
385
|
+
|
|
386
|
+
// Lifecycle
|
|
387
|
+
shutdown(): Promise<void>
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## 8. Common Patterns
|
|
394
|
+
|
|
395
|
+
### Multi-tenant Job Dispatch
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
const jobs = IgniterJobs.create()
|
|
399
|
+
.withAdapter(adapter)
|
|
400
|
+
.addQueue(emailQueue)
|
|
401
|
+
.addScope('organization', {
|
|
402
|
+
resolver: (id) => db.org.findUnique({ where: { id } }),
|
|
403
|
+
})
|
|
404
|
+
.addActor('user', {
|
|
405
|
+
resolver: (id) => db.user.findUnique({ where: { id } }),
|
|
406
|
+
})
|
|
407
|
+
.build()
|
|
408
|
+
|
|
409
|
+
// Dispatch with scope/actor
|
|
410
|
+
await jobs.email.sendWelcome.dispatch(
|
|
411
|
+
{ email: 'test@example.com' },
|
|
412
|
+
{
|
|
413
|
+
scope: { type: 'organization', id: 'org-123' },
|
|
414
|
+
actor: { type: 'user', id: 'user-456' },
|
|
415
|
+
}
|
|
416
|
+
)
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Job With Progress Updates
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
const queue = IgniterQueue.create('exports')
|
|
423
|
+
.addJob('generateReport', {
|
|
424
|
+
schema: z.object({ reportId: z.string() }),
|
|
425
|
+
handler: async ({ data, updateProgress, log }) => {
|
|
426
|
+
await updateProgress(10)
|
|
427
|
+
await log('info', 'Starting report generation')
|
|
428
|
+
|
|
429
|
+
// ... process
|
|
430
|
+
|
|
431
|
+
await updateProgress(50)
|
|
432
|
+
await log('info', 'Halfway done')
|
|
433
|
+
|
|
434
|
+
// ... finish
|
|
435
|
+
|
|
436
|
+
await updateProgress(100)
|
|
437
|
+
return { success: true }
|
|
438
|
+
},
|
|
439
|
+
})
|
|
440
|
+
.build()
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Scheduled Jobs
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
// Schedule at specific time
|
|
447
|
+
await jobs.email.sendWelcome.schedule({
|
|
448
|
+
data: { email: 'test@example.com' },
|
|
449
|
+
at: new Date('2025-12-25T00:00:00Z'),
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
// Schedule with delay
|
|
453
|
+
await jobs.email.sendWelcome.schedule({
|
|
454
|
+
data: { email: 'test@example.com' },
|
|
455
|
+
delay: 60000, // 1 minute
|
|
456
|
+
})
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Worker with Rate Limiting
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
const worker = await jobs.worker
|
|
463
|
+
.forQueues(['email'])
|
|
464
|
+
.withConcurrency(10)
|
|
465
|
+
.withLimiter({
|
|
466
|
+
max: 100, // max jobs
|
|
467
|
+
duration: 60000, // per minute
|
|
468
|
+
})
|
|
469
|
+
.withLockDuration(30000)
|
|
470
|
+
.onIdle(() => console.log('No jobs to process'))
|
|
471
|
+
.start()
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## 9. Version History
|
|
477
|
+
|
|
478
|
+
### 0.1.0 (Initial Release)
|
|
479
|
+
|
|
480
|
+
- ✅ IgniterQueue builder with addJob/addCron
|
|
481
|
+
- ✅ IgniterJobs builder with full configuration
|
|
482
|
+
- ✅ IgniterWorker builder with fluent API
|
|
483
|
+
- ✅ Proxy-based runtime for type-safe access
|
|
484
|
+
- ✅ BullMQ adapter with full feature support
|
|
485
|
+
- ✅ Memory adapter for testing
|
|
486
|
+
- ✅ Scope and actor support
|
|
487
|
+
- ✅ Event subscription system
|
|
488
|
+
- ✅ Job and queue search
|
|
489
|
+
- ✅ Error codes and classes
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## 10. Troubleshooting
|
|
494
|
+
|
|
495
|
+
### Common Issues
|
|
496
|
+
|
|
497
|
+
**"JOBS_MISSING_ADAPTER"**
|
|
498
|
+
- Ensure `withAdapter()` is called before `build()`
|
|
499
|
+
- Check adapter is properly instantiated
|
|
500
|
+
|
|
501
|
+
**"JOBS_QUEUE_NOT_FOUND"**
|
|
502
|
+
- Queue must be registered with `addQueue()`
|
|
503
|
+
- Check queue name spelling
|
|
504
|
+
|
|
505
|
+
**"JOBS_JOB_VALIDATION_FAILED"**
|
|
506
|
+
- Payload doesn't match Zod schema
|
|
507
|
+
- Check `details.issues` for validation errors
|
|
508
|
+
|
|
509
|
+
**TypeScript errors on dispatch**
|
|
510
|
+
- Ensure queue is added before build
|
|
511
|
+
- Check job name exists in queue
|
|
512
|
+
- Verify payload matches schema
|
|
513
|
+
|
|
514
|
+
### Debug Tips
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
// Enable BullMQ debug logging
|
|
518
|
+
process.env.DEBUG = 'bullmq:*'
|
|
519
|
+
|
|
520
|
+
// Check job state
|
|
521
|
+
const state = await jobs.job.state('queue', 'job-id')
|
|
522
|
+
console.log('Job state:', state)
|
|
523
|
+
|
|
524
|
+
// Get job logs
|
|
525
|
+
const logs = await jobs.job.logs('queue', 'job-id')
|
|
526
|
+
console.log('Job logs:', logs)
|
|
527
|
+
|
|
528
|
+
// Subscribe to all events
|
|
529
|
+
await jobs.subscribe('*', (event) => {
|
|
530
|
+
console.log('Event:', event.type, event.data)
|
|
531
|
+
})
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## 11. Dependencies
|
|
537
|
+
|
|
538
|
+
### Peer Dependencies
|
|
539
|
+
|
|
540
|
+
| Package | Version | Purpose |
|
|
541
|
+
|---------|---------|---------|
|
|
542
|
+
| `bullmq` | `^5.0.0` | Job queue implementation |
|
|
543
|
+
| `ioredis` | `^5.0.0` | Redis client |
|
|
544
|
+
| `zod` | `^3.0.0` | Schema validation |
|
|
545
|
+
| `@igniter-js/telemetry` | `^0.1.0` | Optional tracing |
|
|
546
|
+
|
|
547
|
+
### Dev Dependencies
|
|
548
|
+
|
|
549
|
+
| Package | Version | Purpose |
|
|
550
|
+
|---------|---------|---------|
|
|
551
|
+
| `typescript` | `^5.0.0` | TypeScript compiler |
|
|
552
|
+
| `vitest` | `^1.0.0` | Testing framework |
|
|
553
|
+
| `tsup` | `^8.0.0` | Build tool |
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
**Remember:** Always follow existing patterns. When in doubt, check how similar features are implemented in `@igniter-js/store` or `@igniter-js/core`.
|