@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/README.md ADDED
@@ -0,0 +1,321 @@
1
+ # Heracles
2
+
3
+ > Robust background job processing for Elysium.js applications
4
+
5
+ Heracles is a powerful background job processing system for Elysium.js applications. It provides a flexible and scalable solution for running tasks in the background, managing queues, and distributing workloads across multiple workers using Redis as the transport.
6
+
7
+ ## Features
8
+
9
+ - **Job queues**: Organize jobs into different queues with custom settings
10
+ - **Transports**: Abstract communication layer between queues and workers
11
+ - **Worker pool**: Efficiently coordinate workers across multiple processes or servers
12
+ - **Scheduling**: Schedule jobs to run at specific times
13
+ - **Retries**: Automatically retry failed jobs with configurable backoff
14
+ - **Prioritization**: Assign priorities to jobs within a queue
15
+ - **CLI tool**: Manage workers through a simple command-line interface
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ bun add @elysiumjs/heracles
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### 1. Create a Job
26
+
27
+ ```typescript
28
+ import { Job } from '@elysiumjs/heracles';
29
+
30
+ @Job.register({
31
+ queue: 'emails',
32
+ maxRetries: 3,
33
+ retryDelay: 5000
34
+ })
35
+ export class SendEmailJob extends Job {
36
+ constructor(
37
+ private readonly email: string,
38
+ private readonly subject: string,
39
+ private readonly body: string
40
+ ) {
41
+ super();
42
+ }
43
+
44
+ protected async execute(): Promise<void> {
45
+ // Implementation for sending an email
46
+ console.log(`Sending email to ${this.email}: ${this.subject}`);
47
+
48
+ // Simulate email sending
49
+ await new Promise((resolve) => setTimeout(resolve, 1000));
50
+
51
+ console.log(`Email sent successfully to ${this.email}`);
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### 2. Dispatch a Job
57
+
58
+ ```typescript
59
+ import { Queue, RedisTransport } from '@elysiumjs/heracles';
60
+
61
+ import { SendEmailJob } from './jobs/send-email.job';
62
+
63
+ // Configure the queue with Redis transport
64
+ const emailQueue = Queue.get('emails', {
65
+ transport: RedisTransport,
66
+ transportOptions: {
67
+ connection: 'default'
68
+ }
69
+ });
70
+
71
+ // Dispatch a job
72
+ await emailQueue.dispatch(SendEmailJob, [
73
+ 'user@example.com',
74
+ 'Welcome!',
75
+ 'Welcome to our platform!'
76
+ ]);
77
+
78
+ // Dispatch with options
79
+ await emailQueue.dispatch(
80
+ SendEmailJob,
81
+ ['user@example.com', 'Welcome!', 'Welcome to our platform!'],
82
+ {
83
+ priority: 5, // Higher priority (lower number)
84
+ scheduledFor: new Date(Date.now() + 60000), // Run after 1 minute
85
+ maxRetries: 5 // Override max retries
86
+ }
87
+ );
88
+ ```
89
+
90
+ ### 3. Start Workers
91
+
92
+ Using the CLI:
93
+
94
+ ```bash
95
+ # Start a Redis worker for the 'emails' queue with concurrency of 3 jobs
96
+ bun heracles work --id worker-1 --queues=emails --concurrency=3 --redis=default
97
+
98
+ # Start workers for multiple queues
99
+ bun heracles work --id worker-2 --queues=emails,notifications --redis=default
100
+ ```
101
+
102
+ Or programmatically:
103
+
104
+ ```typescript
105
+ import { RedisWorker } from '@elysiumjs/heracles';
106
+
107
+ // Create and start a Redis worker
108
+ const worker = new RedisWorker('default', { id: 'worker-1' });
109
+ await worker.createQueue({ name: 'emails', concurrency: 3 });
110
+ await worker.start();
111
+ ```
112
+
113
+ ## Configuration
114
+
115
+ ### Queue Options
116
+
117
+ ```typescript
118
+ const queue = Queue.get('emails', {
119
+ // Maximum number of concurrent jobs to process in this queue
120
+ concurrency: 5,
121
+
122
+ // Maximum number of retries for failed jobs
123
+ maxRetries: 3,
124
+
125
+ // Delay in milliseconds between retries
126
+ retryDelay: 5000,
127
+
128
+ // Whether to pause processing when an error occurs
129
+ pauseOnError: false,
130
+
131
+ // Redis transport configuration
132
+ transport: RedisTransport,
133
+
134
+ // Transport-specific options
135
+ transportOptions: {
136
+ connection: 'default'
137
+ }
138
+ });
139
+ ```
140
+
141
+ ### Redis Transport Configuration
142
+
143
+ Heracles uses Redis as its transport layer for job distribution, enabling distributed processing across multiple servers or processes. It uses Redis Streams for reliable message delivery and job coordination.
144
+
145
+ #### 1. Configure Redis Connection
146
+
147
+ First, configure a Redis connection in your Elysium.js application:
148
+
149
+ ```typescript
150
+ import { Redis } from '@elysiumjs/core';
151
+
152
+ // Register a Redis connection
153
+ Redis.registerConnection('default', {
154
+ url: 'redis://localhost:6379'
155
+ // Other Redis options
156
+ });
157
+ ```
158
+
159
+ #### 2. Configure Queues with Redis Transport
160
+
161
+ ```typescript
162
+ import { Queue, RedisTransport } from '@elysiumjs/heracles';
163
+
164
+ const queue = Queue.get('emails', {
165
+ transport: RedisTransport,
166
+ transportOptions: {
167
+ connection: 'default', // Redis connection name
168
+ keyPrefix: 'myapp:jobs', // Prefix for Redis keys (default: 'elysium:heracles')
169
+ consumerGroup: 'workers', // Redis consumer group name (default: 'workers')
170
+ pollInterval: 1000, // Poll interval in ms (default: 1000)
171
+ statusTTL: 86400, // Job status TTL in seconds (default: 86400 - 24 hours)
172
+ cleanupCompletedJobs: true, // Auto-cleanup completed jobs (default: true)
173
+ completedJobRetention: 3600, // Time to retain completed jobs in seconds (default: 3600 - 1 hour)
174
+ maxStreamSize: 1000 // Maximum stream size (default: 1000)
175
+ }
176
+ });
177
+ ```
178
+
179
+ #### 3. Worker Configuration
180
+
181
+ Configure workers to process jobs from Redis queues:
182
+
183
+ ```typescript
184
+ import { RedisWorker } from '@elysiumjs/heracles';
185
+
186
+ // Create a Redis worker with a unique ID
187
+ const worker = new RedisWorker('default', {
188
+ id: 'worker-1', // Unique worker ID
189
+ consumerName: 'worker-1', // Unique consumer name (optional)
190
+ keyPrefix: 'myapp:jobs' // Use same prefix as queue configuration
191
+ });
192
+
193
+ // Configure queue settings
194
+ await worker.createQueue({
195
+ name: 'emails',
196
+ concurrency: 5, // Process 5 jobs concurrently
197
+ maxRetries: 3, // Retry failed jobs up to 3 times
198
+ retryDelay: 5000, // Wait 5 seconds between retries
199
+ pauseOnError: false // Don't pause queue on error
200
+ });
201
+
202
+ // Start the worker
203
+ await worker.start();
204
+ ```
205
+
206
+ ## Job Lifecycle
207
+
208
+ Jobs in Heracles go through several statuses:
209
+
210
+ 1. **PENDING**: Job is queued but not yet started
211
+ 2. **RUNNING**: Job is currently being processed
212
+ 3. **COMPLETED**: Job has successfully completed
213
+ 4. **FAILED**: Job has failed (may be retried if retries are available)
214
+ 5. **CANCELLED**: Job was cancelled and won't be processed
215
+ 6. **SCHEDULED_FOR_RETRY**: Job has failed and is scheduled for retry
216
+
217
+ ## Advanced Usage
218
+
219
+ ### Job Cancellation
220
+
221
+ ```typescript
222
+ // Cancel a specific job
223
+ const cancelled = await queue.cancelJob('job_123456789');
224
+
225
+ // Cancel all jobs in a queue
226
+ const cancelledCount = await queue.cancelAllJobs();
227
+ ```
228
+
229
+ ### Queue Management
230
+
231
+ ```typescript
232
+ // Pause a queue (stop processing new jobs)
233
+ await queue.pause();
234
+
235
+ // Resume a paused queue
236
+ await queue.resume();
237
+
238
+ // Drain a queue (complete current jobs but don't accept new ones)
239
+ await queue.drain();
240
+
241
+ // Clear all jobs from a queue
242
+ await queue.clear();
243
+ ```
244
+
245
+ ### Worker Pool
246
+
247
+ The worker pool manages worker availability and distributes jobs using a round-robin algorithm:
248
+
249
+ ```typescript
250
+ import { ThreadWorker, WorkerPool } from '@elysiumjs/heracles';
251
+
252
+ // Get the worker pool instance
253
+ const pool = WorkerPool.instance;
254
+
255
+ // Add a worker to the pool
256
+ const worker = new ThreadWorker(['emails']);
257
+ await worker.start();
258
+ await pool.addWorker(worker.getInfo(), ['emails']);
259
+
260
+ // Get workers for a specific queue
261
+ const emailWorkers = pool.getWorkersForQueue('emails');
262
+ ```
263
+
264
+ ## CLI Reference
265
+
266
+ Heracles includes a CLI tool for managing workers and Redis maintenance:
267
+
268
+ ```
269
+ Usage: heracles [options] [command]
270
+
271
+ Options:
272
+ -V, --version output the version number
273
+ -h, --help display help for command
274
+
275
+ Commands:
276
+ work [options] Start a Redis worker for specific queues
277
+ cleanup [options] Clean up Redis streams
278
+ help [command] display help for command
279
+ ```
280
+
281
+ ### Start Workers
282
+
283
+ ```
284
+ Usage: heracles work [options]
285
+
286
+ Start a Redis worker for specific queues
287
+
288
+ Options:
289
+ --id <ID> Unique identifier for this worker (required)
290
+ -q, --queues <queues> Comma-separated list of queues (default: "default")
291
+ -c, --concurrency <count> Number of concurrent jobs per worker (default: "1")
292
+ -r, --redis <n> Redis connection name (default: "default")
293
+ --config <path> Path to configuration file (default: "")
294
+ --max-retries <count> Maximum retries for failed jobs (default: "3")
295
+ --retry-delay <ms> Delay between retries in milliseconds (default: "5000")
296
+ --pause-on-error Pause queue when error occurs (default: false)
297
+ -h, --help display help for command
298
+ ```
299
+
300
+ ### Clean Up Redis Streams
301
+
302
+ ```
303
+ Usage: heracles cleanup [options]
304
+
305
+ Clean up Redis streams by removing completed and failed jobs
306
+
307
+ Options:
308
+ -r, --redis <name> Redis connection name (default: "default")
309
+ -q, --queues <queues> Comma-separated list of queues (all if not specified)
310
+ -a, --all Remove all entries, not just completed ones (default: false)
311
+ -k, --keyprefix <prefix> Redis key prefix (default: "elysium:heracles")
312
+ -t, --retention <seconds> Time to retain completed jobs in seconds (default: "3600")
313
+ -m, --max <count> Maximum stream size to trim to (default: "1000")
314
+ -s, --status-only Only clean up job status keys, not stream entries (default: false)
315
+ --dry-run Show what would be removed without actually removing (default: false)
316
+ -h, --help display help for command
317
+ ```
318
+
319
+ ## License
320
+
321
+ Apache-2.0