@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 +321 -0
- package/USAGE.md +527 -0
- package/index.ts +16 -0
- package/package.json +43 -0
- package/src/heracles.ts +68 -0
- package/src/index.ts +28 -0
- package/src/job.ts +413 -0
- package/src/queue.ts +567 -0
- package/src/transport.ts +518 -0
- package/src/transports/redis.transport.ts +1558 -0
- package/src/utils.ts +61 -0
- package/src/worker.ts +312 -0
- package/src/workers/base.worker.ts +804 -0
- package/src/workers/redis.worker.ts +523 -0
- package/tsconfig.json +47 -0
- package/types.d.ts +21 -0
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
|