@elysiumjs/heracles 0.4.1

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/USAGE.md ADDED
@@ -0,0 +1,527 @@
1
+ # Heracles Usage Guide
2
+
3
+ This document provides a practical guide to using the Heracles job processing framework in your Elysium.js application.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @elysiumjs/heracles
9
+ ```
10
+
11
+ ## Basic Concepts
12
+
13
+ - **Jobs**: Background tasks defined as classes
14
+ - **Queues**: Lists of jobs waiting to be processed
15
+ - **Workers**: Processes that execute jobs from queues
16
+ - **Transports**: Communication channels between queues and workers
17
+ - **Worker Pool**: Efficiently distributes jobs to workers
18
+
19
+ ## Creating Jobs
20
+
21
+ Jobs are defined as classes that extend the `Job` base class:
22
+
23
+ ```typescript
24
+ import { Job } from '@elysiumjs/heracles';
25
+
26
+ @Job.register({
27
+ queue: 'emails', // Queue to process this job
28
+ maxRetries: 3, // Max retry attempts
29
+ retryDelay: 5000 // Delay between retries (ms)
30
+ })
31
+ export class SendEmailJob extends Job {
32
+ constructor(
33
+ private readonly to: string,
34
+ private readonly subject: string,
35
+ private readonly body: string
36
+ ) {
37
+ super(); // Required
38
+ }
39
+
40
+ protected async execute(): Promise<void> {
41
+ // Your job implementation here
42
+ console.log(`Sending email to ${this.to}: ${this.subject}`);
43
+
44
+ // Use this.debug(), this.info(), this.warning(), this.error() for logging
45
+ this.info(`Email sent successfully to ${this.to}`);
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## Dispatching Jobs
51
+
52
+ ```typescript
53
+ import { Queue, RedisTransport } from '@elysiumjs/heracles';
54
+
55
+ import { SendEmailJob } from './jobs/send-email.job';
56
+
57
+ // Get the queue with Redis transport
58
+ const emailQueue = Queue.get('emails', {
59
+ transport: RedisTransport,
60
+ transportOptions: {
61
+ connection: 'default' // Redis connection name
62
+ }
63
+ });
64
+
65
+ // Dispatch a job
66
+ await emailQueue.dispatch(SendEmailJob, [
67
+ 'user@example.com',
68
+ 'Welcome!',
69
+ 'Welcome to our service!'
70
+ ]);
71
+
72
+ // With additional options
73
+ await emailQueue.dispatch(
74
+ SendEmailJob,
75
+ ['user@example.com', 'Welcome!', 'Welcome to our service!'],
76
+ {
77
+ priority: 5, // Higher priority (lower number)
78
+ scheduledFor: new Date(Date.now() + 3600000), // Run in 1 hour
79
+ maxRetries: 5, // Override max retries
80
+ retryDelay: 10000 // Override retry delay
81
+ }
82
+ );
83
+ ```
84
+
85
+ ## Queue Management
86
+
87
+ ```typescript
88
+ // Create a custom queue with Redis transport
89
+ const queue = Queue.get('emails', {
90
+ concurrency: 5, // Process 5 jobs simultaneously
91
+ maxRetries: 3, // Default retries for failed jobs
92
+ retryDelay: 5000, // Default delay between retries
93
+ pauseOnError: false, // Don't pause on error
94
+ transport: RedisTransport, // Redis transport
95
+ transportOptions: {
96
+ // Transport-specific options
97
+ connection: 'default',
98
+ keyPrefix: 'myapp:jobs'
99
+ }
100
+ });
101
+
102
+ // Queue operations
103
+ await queue.pause(); // Pause processing
104
+ await queue.resume(); // Resume processing
105
+ await queue.drain(); // Complete current jobs, don't accept new ones
106
+ await queue.clear(); // Clear all jobs from queue
107
+ await queue.cancelJob('job_id'); // Cancel specific job
108
+ await queue.cancelAllJobs(); // Cancel all jobs
109
+ ```
110
+
111
+ ## Starting Workers
112
+
113
+ ### Using the CLI
114
+
115
+ ```bash
116
+ # Start a Redis worker for one queue
117
+ bun heracles work --id worker-1 --queues=emails --concurrency=3 --redis=default
118
+
119
+ # Start a Redis worker for multiple queues
120
+ bun heracles work --id worker-2 --queues=emails,notifications --redis=default --concurrency=4
121
+ ```
122
+
123
+ CLI options:
124
+
125
+ - `--id`: Unique identifier for this worker (required)
126
+ - `--queues`: Comma-separated list of queues (default: "default")
127
+ - `--concurrency`: Number of concurrent jobs per worker (default: 1)
128
+ - `--redis`: Redis connection name (default: "default")
129
+ - `--max-retries`: Maximum retries for failed jobs (default: 3)
130
+ - `--retry-delay`: Delay between retries in milliseconds (default: 5000)
131
+ - `--pause-on-error`: Pause queue when error occurs (default: false)
132
+ - `--config`: Path to configuration file for more complex setups
133
+
134
+ ### Programmatically
135
+
136
+ ```typescript
137
+ import { RedisWorker } from '@elysiumjs/heracles';
138
+
139
+ // Create a Redis worker with a unique ID
140
+ const worker = new RedisWorker('default', { id: 'worker-1' });
141
+
142
+ // Add queues to the worker
143
+ await worker.createQueue({
144
+ name: 'emails',
145
+ concurrency: 3,
146
+ maxRetries: 5,
147
+ retryDelay: 5000
148
+ });
149
+
150
+ // Start the worker
151
+ await worker.start();
152
+ ```
153
+
154
+ ## Redis Setup
155
+
156
+ Heracles uses Redis Streams as its transport layer, enabling distributed job processing across multiple servers, applications, or processes. This section explains how to set up and configure Redis for Heracles.
157
+
158
+ ### 1. Configure Redis Connection
159
+
160
+ First, register a Redis connection in your application:
161
+
162
+ ```typescript
163
+ import { Redis } from '@elysiumjs/core';
164
+
165
+ // Register a Redis connection
166
+ Redis.registerConnection('default', {
167
+ url: 'redis://localhost:6379'
168
+ // Other Redis options like password, tls, etc.
169
+ });
170
+ ```
171
+
172
+ ### 2. Configure Queue with Redis
173
+
174
+ Configure your queues to use Redis:
175
+
176
+ ```typescript
177
+ import { Queue, RedisTransport } from '@elysiumjs/heracles';
178
+
179
+ const queue = Queue.get('emails', {
180
+ transport: RedisTransport,
181
+ transportOptions: {
182
+ connection: 'default', // Redis connection name
183
+ keyPrefix: 'myapp:jobs', // Prefix for Redis keys (default: 'elysium:heracles')
184
+ consumerGroup: 'workers', // Redis consumer group name (default: 'workers')
185
+
186
+ // Stream cleanup options
187
+ cleanupCompletedJobs: true, // Auto-cleanup completed jobs (default: true)
188
+ completedJobRetention: 3600, // Seconds to keep completed jobs (default: 3600 - 1 hour)
189
+ maxStreamSize: 1000, // Maximum stream size to maintain (default: 1000)
190
+
191
+ // Advanced options
192
+ pollInterval: 1000, // Polling interval in milliseconds (default: 1000)
193
+ batchSize: 10, // Batch size for reading messages (default: 10)
194
+ statusTTL: 86400, // Time to live for job status in seconds (default: 86400 - 24 hours)
195
+ consumerName: 'consumer-xyz' // Unique consumer name (optional, auto-generated if not provided)
196
+ }
197
+ });
198
+ ```
199
+
200
+ ### 3. Understanding Heracles Architecture
201
+
202
+ Heracles uses Redis Streams as the message broker for job coordination:
203
+
204
+ - **Producer Mode**: The application that dispatches jobs operates as a producer
205
+ - **Consumer Mode**: Worker processes operate as consumers that process jobs
206
+ - **Job Status Storage**: Each job's status is stored in a Redis hash for quick updates
207
+ - **Streams**: One stream per queue for reliable, ordered message delivery
208
+ - **Consumer Groups**: Ensures each job is processed by only one worker
209
+
210
+ ### 4. Efficient Storage Architecture
211
+
212
+ Heracles implements an efficient Redis storage strategy:
213
+
214
+ - **Status Hashes**: Job status is tracked in dedicated Redis hashes for quick updates
215
+ - **Minimal Storage**: Single entry per job in the Redis stream to minimize storage usage
216
+ - **In-place Updates**: Status updates modify the existing job status hash instead of creating new entries
217
+ - **Automatic Cleanup**: Background process runs every 5 minutes, removing completed job entries older than the retention period
218
+ - **Stream Trimming**: Streams are automatically trimmed to the maximum size to prevent unbounded growth
219
+ - **Job Locking**: Support for job locking to prevent concurrent execution of jobs with the same ID
220
+
221
+ ## Job Status Lifecycle
222
+
223
+ 1. **PENDING**: Job is queued but not yet started
224
+ 2. **RUNNING**: Job is currently executing
225
+ 3. **COMPLETED**: Job completed successfully
226
+ 4. **FAILED**: Job failed (may be retried if retries available)
227
+ 5. **CANCELLED**: Job was cancelled
228
+ 6. **SCHEDULED_FOR_RETRY**: Job failed and scheduled for retry
229
+
230
+ ## Deployment Strategies
231
+
232
+ ### Distributed Deployment
233
+
234
+ Heracles is designed for distributed deployment across multiple servers, processes, or applications:
235
+
236
+ #### 1. Configure Redis in Applications
237
+
238
+ In all applications that dispatch or process jobs:
239
+
240
+ ```typescript
241
+ import { Redis } from '@elysiumjs/core';
242
+
243
+ // Register the same Redis connection across all applications
244
+ Redis.registerConnection('default', {
245
+ url: 'redis://your-redis-server:6379'
246
+ });
247
+ ```
248
+
249
+ #### 2. Configure Job Dispatch in Producer Applications
250
+
251
+ ```typescript
252
+ import { Queue, RedisTransport } from '@elysiumjs/heracles';
253
+
254
+ // Create queues with Redis transport
255
+ const emailQueue = Queue.get('emails', {
256
+ transport: RedisTransport,
257
+ transportOptions: {
258
+ connection: 'default',
259
+ keyPrefix: 'myapp:jobs' // Use consistent prefix across all applications
260
+ }
261
+ });
262
+
263
+ // Dispatch jobs as usual
264
+ await emailQueue.dispatch(SendEmailJob, [
265
+ 'user@example.com',
266
+ 'Welcome!',
267
+ 'Welcome to our service!'
268
+ ]);
269
+ ```
270
+
271
+ #### 3. Start Workers on Multiple Servers
272
+
273
+ ```bash
274
+ # Server 1 (handles email jobs)
275
+ bun heracles work --id worker-emails-1 --queues=emails --redis=default --concurrency=4
276
+
277
+ # Server 2 (handles notification jobs)
278
+ bun heracles work --id worker-notifications-1 --queues=notifications --redis=default --concurrency=4
279
+
280
+ # Server 3 (handles heavy processing jobs)
281
+ bun heracles work --id worker-processing-1 --queues=processing --redis=default --concurrency=1
282
+ ```
283
+
284
+ #### 4. Start Workers Programmatically
285
+
286
+ For more control, you can start workers programmatically:
287
+
288
+ ```typescript
289
+ import { RedisWorker } from '@elysiumjs/heracles';
290
+
291
+ // Create worker for specific queues
292
+ const worker = new RedisWorker('default', {
293
+ id: 'worker-emails-1', // Unique worker ID
294
+ keyPrefix: 'myapp:jobs' // Match queue prefix
295
+ });
296
+
297
+ // Configure queues with specific settings
298
+ await worker.createQueue({
299
+ name: 'emails',
300
+ concurrency: 4,
301
+ maxRetries: 5,
302
+ retryDelay: 10000
303
+ });
304
+
305
+ // Start the worker
306
+ await worker.start();
307
+
308
+ // Graceful shutdown
309
+ process.on('SIGTERM', async () => {
310
+ await worker.stop(false); // false = finish processing current jobs
311
+ });
312
+ ```
313
+
314
+ ## Monitoring and Maintenance
315
+
316
+ When running Heracles in production, proper monitoring and maintenance is essential.
317
+
318
+ ### Automatic Maintenance
319
+
320
+ Heracles automatically manages Redis streams:
321
+
322
+ 1. **Auto Cleanup**: Every 5 minutes, completed jobs older than the retention period are removed
323
+ 2. **Stream Trimming**: Streams are trimmed to the maximum size to prevent unbounded growth
324
+ 3. **Status TTL**: Job status records have a configurable TTL (default: 24 hours)
325
+
326
+ ### Manual Cleanup with CLI
327
+
328
+ For manual maintenance or scheduled cleanup, use the CLI:
329
+
330
+ ```bash
331
+ # Basic cleanup with default settings
332
+ bun heracles cleanup --redis=default
333
+
334
+ # Targeted cleanup for specific queues
335
+ bun heracles cleanup --redis=default --queues=emails,notifications \
336
+ --keyprefix=myapp:jobs --retention=3600 --max=1000
337
+
338
+ # Only clean up job status keys, preserve stream entries
339
+ bun heracles cleanup --status-only
340
+
341
+ # Preview what would be removed without making changes
342
+ bun heracles cleanup --dry-run
343
+
344
+ # Remove all entries from streams (use with caution!)
345
+ bun heracles cleanup --all
346
+ ```
347
+
348
+ #### Cleanup Command Options
349
+
350
+ | Option | Description | Default |
351
+ | --------------- | ---------------------------------------------------- | ------------------ |
352
+ | `--redis` | Redis connection name | "default" |
353
+ | `--queues` | Comma-separated list of queues to clean up | All queues |
354
+ | `--keyprefix` | Redis key prefix | "elysium:heracles" |
355
+ | `--retention` | Seconds to retain completed jobs before removal | 3600 (1 hour) |
356
+ | `--max` | Maximum stream size to trim to | 1000 |
357
+ | `--status-only` | Only clean up job status keys, not stream entries | false |
358
+ | `--dry-run` | Show what would be removed without actually removing | false |
359
+ | `--all` | Remove all entries, not just completed ones | false |
360
+
361
+ ### Monitoring Redis Keys
362
+
363
+ Heracles uses the following Redis key patterns:
364
+
365
+ - `{keyPrefix}:stream:{queueName}` - Redis streams for each queue
366
+ - `{keyPrefix}:status:{queueName}:{jobId}:{dispatchId}` - Job status hashes
367
+ - `{keyPrefix}:lock:{queueName}:{jobId}` - Locks for NO_OVERLAP jobs
368
+ - `{keyPrefix}:worker:{workerId}` - Worker registration information
369
+
370
+ You can monitor these using Redis CLI or monitoring tools:
371
+
372
+ ```bash
373
+ # Count stream entries
374
+ redis-cli XLEN elysium:heracles:stream:emails
375
+
376
+ # View active workers
377
+ redis-cli KEYS elysium:heracles:worker:*
378
+
379
+ # Count job status records
380
+ redis-cli KEYS elysium:heracles:status:emails:* | wc -l
381
+ ```
382
+
383
+ ## Advanced Features
384
+
385
+ ### Job Overlap Behavior Control
386
+
387
+ You can control how multiple instances of the same job are handled using the `JobOverlapBehavior` setting:
388
+
389
+ ```typescript
390
+ import { Job, JobOverlapBehavior } from '@elysiumjs/heracles';
391
+
392
+ @Job.register({
393
+ queue: 'emails',
394
+ overlapBehavior: JobOverlapBehavior.NO_OVERLAP, // Prevent parallel execution of same job ID
395
+ overlapDelay: 5000 // Wait 5 seconds after job completion before starting next one
396
+ })
397
+ export class SendEmailJob extends Job {
398
+ // Job implementation...
399
+ }
400
+ ```
401
+
402
+ This ensures that even across multiple workers on different servers, only one instance of a job with the same ID runs at a time.
403
+
404
+ ### Advanced Redis Configuration
405
+
406
+ For advanced Redis setups like Redis Cluster or Sentinel, configure the Redis connection appropriately:
407
+
408
+ ```typescript
409
+ import { Redis } from '@elysiumjs/core';
410
+
411
+ // Example with Redis Sentinel
412
+ Redis.registerConnection('sentinel', {
413
+ sentinel: {
414
+ sentinels: [
415
+ { host: '192.168.1.1', port: 26379 },
416
+ { host: '192.168.1.2', port: 26379 }
417
+ ],
418
+ name: 'mymaster'
419
+ },
420
+ password: 'your-password'
421
+ });
422
+
423
+ // Use in queue configuration
424
+ const queue = Queue.get('emails', {
425
+ transport: RedisTransport,
426
+ transportOptions: {
427
+ connection: 'sentinel'
428
+ // Other options...
429
+ }
430
+ });
431
+ ```
432
+
433
+ ### Worker Pool Management
434
+
435
+ When running multiple workers, they efficiently distribute workload through Redis:
436
+
437
+ ```typescript
438
+ import { RedisWorker } from '@elysiumjs/heracles';
439
+
440
+ // Create multiple workers for the same queues
441
+ const worker1 = new RedisWorker('default', { id: 'worker-1' });
442
+ const worker2 = new RedisWorker('default', { id: 'worker-2' });
443
+
444
+ // Register both for the same queues
445
+ await worker1.createQueue({ name: 'emails', concurrency: 3 });
446
+ await worker2.createQueue({ name: 'emails', concurrency: 3 });
447
+
448
+ // Start both workers
449
+ await worker1.start();
450
+ await worker2.start();
451
+
452
+ // Jobs dispatched to the 'emails' queue will be automatically
453
+ // distributed between worker1 and worker2 by Redis consumer groups
454
+ ```
455
+
456
+ ## Best Practices
457
+
458
+ 1. **Job Design**: Keep jobs small and focused on a single task
459
+ 2. **Queue Organization**: Group similar jobs in the same queue
460
+ 3. **Error Handling**: Implement proper error handling in your execute method
461
+ 4. **Idempotent Jobs**: Design jobs to be safely retried
462
+ 5. **Monitoring**: Regularly check worker status and queue sizes
463
+ 6. **Resource Management**: Adjust concurrency based on the job's resource requirements
464
+
465
+ ## Error Handling and Retries
466
+
467
+ Heracles automatically handles retries for failed jobs:
468
+
469
+ ```typescript
470
+ @Job.register({
471
+ queue: 'emails',
472
+ maxRetries: 5, // Max retry attempts
473
+ retryDelay: 10000 // 10 seconds between retries
474
+ })
475
+ export class SendEmailJob extends Job {
476
+ protected async execute(): Promise<void> {
477
+ try {
478
+ // Your job logic
479
+ } catch (error) {
480
+ // Log error details
481
+ this.error(`Failed to send email: ${error.message}`);
482
+
483
+ // Throwing the error will mark the job as failed
484
+ // and trigger retry if retries are available
485
+ throw error;
486
+ }
487
+ }
488
+ }
489
+ ```
490
+
491
+ ## Configuration File for Workers
492
+
493
+ For consistent worker configuration in production environments, create a JSON configuration file:
494
+
495
+ ```json
496
+ {
497
+ "id": "worker-email-prod-1",
498
+ "queues": "emails,notifications,processing",
499
+ "redis": "default",
500
+ "concurrency": 3,
501
+ "maxRetries": 5,
502
+ "retryDelay": 10000,
503
+ "pauseOnError": false,
504
+ "keyPrefix": "myapp:jobs"
505
+ }
506
+ ```
507
+
508
+ Then use it with the CLI:
509
+
510
+ ```bash
511
+ bun heracles work --config=heracles.json
512
+ ```
513
+
514
+ This approach ensures consistent configuration across all worker instances and simplifies deployment scripts.
515
+
516
+ ### Performance Considerations
517
+
518
+ When running Heracles in production:
519
+
520
+ 1. **Redis Connection Pool**: Configure appropriate connection pool size in your Redis client
521
+ 2. **Key Expiration**: Set appropriate retention periods to avoid memory growth
522
+ 3. **Stream Size**: Monitor stream sizes and adjust `maxStreamSize` accordingly
523
+ 4. **Cleanup Schedule**: Run regular cleanup jobs during off-peak hours
524
+ 5. **Concurrency Settings**: Balance worker concurrency based on job complexity and server resources
525
+ 6. **Worker Distribution**: Distribute workers across multiple servers for high availability
526
+
527
+ By following these practices, you can build a robust, scalable job processing system with Heracles.
package/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ // Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ // Re-export all components from src/index.ts
16
+ export * from './src/index';
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@elysiumjs/heracles",
3
+ "version": "0.4.1",
4
+ "description": "Background job processing system for Elysium.js",
5
+ "main": "index.ts",
6
+ "bin": {
7
+ "heracles": "./dist/bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "build:cli": "bun build ./bin/cli.ts --outdir ./dist/bin --target bun -e @elysiumjs/heracles -e @elysiumjs/core",
11
+ "test": "bun test",
12
+ "dev": "bun --watch src/index.ts",
13
+ "clean": "rimraf dist",
14
+ "format": "prettier --write 'src/**/*.{ts,tsx}'",
15
+ "prepublishOnly": "bun run clean && bun run build:cli"
16
+ },
17
+ "keywords": [
18
+ "elysium",
19
+ "job",
20
+ "queue",
21
+ "worker",
22
+ "background",
23
+ "processing",
24
+ "heracles"
25
+ ],
26
+ "author": "Workbud Technologies Inc.",
27
+ "license": "Apache-2.0",
28
+ "dependencies": {
29
+ "@elysiumjs/core": "latest",
30
+ "commander": "^13.1.0",
31
+ "radash": "^12.1.0",
32
+ "reflect-metadata": "^0.2.2"
33
+ },
34
+ "devDependencies": {
35
+ "bun-types": "^1.2.13",
36
+ "prettier": "^3.5.3",
37
+ "rimraf": "^6.0.1",
38
+ "type-fest": "^4.41.0"
39
+ },
40
+ "peerDependencies": {
41
+ "typescript": "^5.8.3"
42
+ }
43
+ }
@@ -0,0 +1,68 @@
1
+ // Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ import type { Job, JobClass } from './job';
16
+ import type { JobDispatchId, JobDispatchOptions } from './queue';
17
+
18
+ import { uid } from 'radash';
19
+
20
+ import { Queue } from './queue';
21
+ import { getJobMetadata } from './utils';
22
+
23
+ export namespace Heracles {
24
+ /**
25
+ * Dispatch a job to be executed asynchronously.
26
+ * @author Axel Nana <axel.nana@workbud.com>
27
+ * @param jobClass The job class to dispatch. Should extend the base {@link Job} class and have the {@link Job.register} decorator set.
28
+ * @param args The arguments to pass to the job constructor.
29
+ * @param options Additional options for the job dispatch.
30
+ * @returns The ID of the dispatched job.
31
+ */
32
+ export const dispatch = async <T extends Job, TClass extends JobClass<T> = JobClass<T>>(
33
+ jobClass: TClass,
34
+ args: ConstructorParameters<TClass> = [] as any,
35
+ options: JobDispatchOptions = {}
36
+ ): Promise<JobDispatchId> => {
37
+ // Check if job class is registered properly
38
+ const metadata = getJobMetadata(jobClass);
39
+ if (!metadata) {
40
+ throw new Error(`Job ${jobClass.name} is not marked with @Job.register() decorator`);
41
+ }
42
+
43
+ if (!metadata.queue) {
44
+ throw new Error(`Job ${jobClass.name} is not registered with a queue`);
45
+ }
46
+
47
+ if (!Queue.exists(metadata.queue)) {
48
+ throw new Error(
49
+ `Queue ${metadata.queue} does not exist. Please create the queue before dispatching the job.`
50
+ );
51
+ }
52
+
53
+ const queue = Queue.get(metadata.queue);
54
+
55
+ // Generate a unique dispatch ID for this job dispatch
56
+ const dispatchId = `dispatch_${Date.now()}_${uid(8)}`;
57
+
58
+ // Include overlap behavior information in the options
59
+ const dispatchOptions = {
60
+ dispatchId,
61
+ overlapBehavior: metadata.overlapBehavior,
62
+ overlapDelay: metadata.overlapDelay,
63
+ ...options
64
+ };
65
+
66
+ return queue.dispatch(jobClass, metadata.name, args, dispatchOptions);
67
+ };
68
+ }
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ // Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ export type { JobProps } from './job';
16
+ export type { JobDispatchOptions, QueueOptions } from './queue';
17
+ export type { JobStatusInfo, Transport, TransportClass, TransportEvent } from './transport';
18
+ export type { QueuedJob, QueueState, Worker, WorkerInfo } from './worker';
19
+ export type { RedisTransportOptions } from './transports/redis.transport';
20
+
21
+ export { Heracles } from './heracles';
22
+ export { Job, JobStatus } from './job';
23
+ export { Queue } from './queue';
24
+ export { TransportMode } from './transport';
25
+ export { RedisTransport } from './transports/redis.transport';
26
+ export { WorkerStatus } from './worker';
27
+ export { BaseWorker } from './workers/base.worker';
28
+ export { RedisWorker } from './workers/redis.worker';