@elysiumjs/heracles 0.4.3 → 0.5.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.
@@ -0,0 +1,216 @@
1
+ import type { Job } from '../job';
2
+ import type { JobDispatchOptions } from '../queue';
3
+ import type { Transport } from '../transport';
4
+ import type { QueueState, Worker, WorkerInfo, WorkerQueueOptions } from '../worker';
5
+ import { InteractsWithConsole } from '@elysiumjs/core';
6
+ import { JobStatus } from '../job';
7
+ import { WorkerStatus } from '../worker';
8
+ /**
9
+ * Base class for workers that manages multiple job queues and processes them in parallel.
10
+ * Each queue processes its jobs sequentially by default, but can be configured for concurrency.
11
+ * @author Axel Nana <axel.nana@workbud.com>
12
+ *
13
+ * @template TTransport The type of transport used by the worker.
14
+ */
15
+ export declare abstract class BaseWorker<TTransport extends Transport> extends InteractsWithConsole implements Worker {
16
+ #private;
17
+ /**
18
+ * Transport instance used for Redis communication
19
+ */
20
+ protected transport: TTransport;
21
+ /**
22
+ * The queues managed by this worker.
23
+ */
24
+ protected queues: Map<string, QueueState>;
25
+ /**
26
+ * The default queue name.
27
+ */
28
+ protected defaultQueueName: string;
29
+ /**
30
+ * The default transport used by this worker.
31
+ */
32
+ protected defaultTransport?: Transport;
33
+ /**
34
+ * The current status of this worker.
35
+ */
36
+ protected workerStatus: WorkerStatus;
37
+ /**
38
+ * When this worker was started.
39
+ */
40
+ protected startedAt: Date;
41
+ /**
42
+ * Interval in milliseconds to check for scheduled jobs.
43
+ */
44
+ protected scheduledJobInterval: number;
45
+ /**
46
+ * Timer for checking scheduled jobs.
47
+ */
48
+ private scheduledJobTimer?;
49
+ constructor(id?: string);
50
+ /**
51
+ * Gets the worker ID.
52
+ * @returns The worker ID.
53
+ */
54
+ get id(): string;
55
+ /**
56
+ * Gets the worker status.
57
+ */
58
+ get status(): WorkerStatus;
59
+ /**
60
+ * Creates a new queue with the specified options.
61
+ *
62
+ * @param options The queue configuration options.
63
+ * @returns The Worker instance for method chaining.
64
+ */
65
+ createQueue(options: WorkerQueueOptions): Promise<Worker>;
66
+ /**
67
+ * Adds a job to the specified queue or the default queue if not specified.
68
+ *
69
+ * @param job The job to add to the queue.
70
+ * @param queueName Optional name of the queue to add the job to. Defaults to the default queue.
71
+ * @param options Additional options for job scheduling
72
+ * @returns The Worker instance for method chaining.
73
+ * @throws Error if the specified queue does not exist.
74
+ */
75
+ addJob(job: Job, queueName?: string, options?: JobDispatchOptions): Promise<Worker>;
76
+ /**
77
+ * Pauses a queue, preventing it from processing new jobs.
78
+ *
79
+ * @param queueName The name of the queue to pause. If not specified, pauses all queues.
80
+ * @returns The Worker instance for method chaining.
81
+ */
82
+ pause(queueName?: string): Promise<Worker>;
83
+ /**
84
+ * Resumes a paused queue.
85
+ *
86
+ * @param queueName The name of the queue to resume. If not specified, resumes all queues.
87
+ * @returns The Worker instance for method chaining.
88
+ */
89
+ resume(queueName?: string): Promise<Worker>;
90
+ /**
91
+ * Drains a queue, completing all current jobs but not accepting new ones.
92
+ *
93
+ * @param queueName The name of the queue to drain. If not specified, drains all queues.
94
+ * @returns The Worker instance for method chaining.
95
+ */
96
+ drain(queueName?: string): Promise<Worker>;
97
+ /**
98
+ * Clears all jobs from a queue.
99
+ *
100
+ * @param queueName The name of the queue to clear. If not specified, clears all queues.
101
+ * @returns The Worker instance for method chaining.
102
+ */
103
+ clear(queueName?: string): Promise<Worker>;
104
+ /**
105
+ * Gets the number of jobs in a queue.
106
+ *
107
+ * @param queueName The name of the queue to get the size of.
108
+ * @returns The number of jobs in the queue.
109
+ * @throws Error if the specified queue does not exist.
110
+ */
111
+ size(queueName?: string): Promise<number>;
112
+ /**
113
+ * Gets the total number of jobs across all queues.
114
+ *
115
+ * @returns The total number of jobs.
116
+ */
117
+ totalSize(): Promise<number>;
118
+ /**
119
+ * Gets statistics about all queues.
120
+ *
121
+ * @returns An object containing statistics about each queue.
122
+ */
123
+ getStats(): Promise<Record<string, {
124
+ waiting: number;
125
+ processing: number;
126
+ paused: boolean;
127
+ draining: boolean;
128
+ }>>;
129
+ /**
130
+ * Gets information about this worker for the worker pool.
131
+ *
132
+ * @returns Worker information object
133
+ */
134
+ getInfo(): WorkerInfo;
135
+ /**
136
+ * Cancels a job by its ID.
137
+ *
138
+ * @param jobId The ID of the job to cancel.
139
+ * @param queueName Optional queue name to search in. If not provided, searches all queues.
140
+ * @returns `true` if the job was found and canceled, false otherwise.
141
+ */
142
+ cancelJob(jobId: string, queueName?: string): Promise<boolean>;
143
+ /**
144
+ * Cancels all jobs in a queue.
145
+ *
146
+ * @param queueName The name of the queue to cancel jobs from. If not provided, cancels jobs in all queues.
147
+ * @returns The number of jobs canceled.
148
+ */
149
+ cancelAllJobs(queueName?: string): Promise<number>;
150
+ /**
151
+ * Get a job by its ID.
152
+ *
153
+ * @param jobId The ID of the job to get.
154
+ * @param queueName Optional queue name to search in. If not provided, searches all queues.
155
+ * @returns The job if found, null otherwise.
156
+ */
157
+ getJob(jobId: string, queueName?: string): Promise<Job | null>;
158
+ /**
159
+ * Start the worker.
160
+ */
161
+ start(): Promise<void>;
162
+ /**
163
+ * Stop the worker.
164
+ *
165
+ * @param force If true, cancel all running jobs. If false, allow them to complete.
166
+ */
167
+ stop(force?: boolean): Promise<void>;
168
+ /**
169
+ * Set the concurrency for a queue.
170
+ *
171
+ * @param queueName The name of the queue.
172
+ * @param concurrency The new concurrency value.
173
+ */
174
+ setConcurrency(queueName: string, concurrency: number): Promise<void>;
175
+ /**
176
+ * Start the timer for checking scheduled jobs.
177
+ */
178
+ private startScheduledJobTimer;
179
+ /**
180
+ * Stop the timer for checking scheduled jobs.
181
+ */
182
+ private stopScheduledJobTimer;
183
+ /**
184
+ * Check for jobs that are scheduled to run now.
185
+ */
186
+ private checkScheduledJobs;
187
+ /**
188
+ * Processes the next job in the specified queue.
189
+ *
190
+ * @param queueName The name of the queue to process.
191
+ */
192
+ protected abstract processNextJob(queueName: string): Promise<void>;
193
+ /**
194
+ * Processes jobs in a queue up to the concurrency limit.
195
+ *
196
+ * @param queueName The name of the queue to process.
197
+ * @returns A promise that resolves when job processing has been initiated.
198
+ */
199
+ protected processQueueJobs(queueName: string): Promise<void>;
200
+ /**
201
+ * Send job status update
202
+ * @param jobId Job ID
203
+ * @param queue Queue name
204
+ * @param status Job status
205
+ * @param error Optional error message
206
+ */
207
+ protected sendJobStatusUpdate(jobId: string, dispatchId: string, queue: string, status: JobStatus, error?: string): Promise<void>;
208
+ /**
209
+ * Cancels a job in a specific queue.
210
+ *
211
+ * @param jobId The ID of the job to cancel.
212
+ * @param queueName The name of the queue to search in.
213
+ * @returns `true` if the job was found and canceled, false otherwise.
214
+ */
215
+ private cancelJobInQueue;
216
+ }
@@ -0,0 +1,57 @@
1
+ import type { QueueOptions } from '../queue';
2
+ import type { Worker } from '../worker';
3
+ import { RedisTransport } from '../transports/redis.transport';
4
+ import { BaseWorker } from './base.worker';
5
+ /**
6
+ * Worker implementation that uses Redis for communication.
7
+ * This worker can run in a separate process from the dispatcher.
8
+ * @author Axel Nana <axel.nana@workbud.com>
9
+ */
10
+ export declare class RedisWorker extends BaseWorker<RedisTransport> {
11
+ /**
12
+ * Whether the worker is currently running
13
+ */
14
+ private isRunning;
15
+ /**
16
+ * Queues registered with this worker
17
+ */
18
+ private registeredQueues;
19
+ /**
20
+ * Creates a new RedisWorker instance
21
+ * @param connectionName Name of the Redis connection to use
22
+ * @param options Additional options for the Redis transport
23
+ */
24
+ constructor(connectionName?: string, options?: Record<string, any>);
25
+ /**
26
+ * Start the worker and begin processing jobs
27
+ */
28
+ start(): Promise<void>;
29
+ /**
30
+ * Stop the worker
31
+ * @param force If true, cancel all jobs in progress
32
+ */
33
+ stop(force?: boolean): Promise<void>;
34
+ /**
35
+ * Process the next job in a queue, respecting overlap settings
36
+ * @param queueName Name of the queue
37
+ */
38
+ protected processNextJob(queueName: string): Promise<void>;
39
+ /**
40
+ * Create a new queue with the specified options
41
+ * @param options Queue options
42
+ */
43
+ createQueue(options: QueueOptions): Promise<Worker>;
44
+ /**
45
+ * Handle a message from the transport
46
+ * @param message The message to handle
47
+ */
48
+ private handleTransportMessage;
49
+ /**
50
+ * Handle a job:process message
51
+ * @param jobName Job class name
52
+ * @param args Job constructor arguments
53
+ * @param queueName Queue name
54
+ * @param options Job options
55
+ */
56
+ private handleProcessJob;
57
+ }
package/package.json CHANGED
@@ -1,24 +1,26 @@
1
1
  {
2
2
  "name": "@elysiumjs/heracles",
3
- "version": "0.4.3",
4
- "description": "Background job processing system for Elysium.js",
5
- "main": "index.ts",
6
- "bin": {
7
- "heracles": "./dist/bin/cli.js"
8
- },
3
+ "version": "0.5.0",
4
+ "description": "Background job processing system for Elysium.js apps.",
5
+ "module": "dist/index.js",
6
+ "type": "module",
7
+ "types": "dist/index.d.ts",
9
8
  "scripts": {
10
- "build:cli": "bun build ./bin/cli.ts --outdir ./dist/bin --target bun -e @elysiumjs/heracles -e @elysiumjs/core",
11
9
  "test": "bun test",
12
10
  "dev": "bun --watch src/index.ts",
13
- "clean": "rimraf dist",
14
11
  "format": "prettier --write 'src/**/*.{ts,tsx}'",
15
- "prepublishOnly": "bun run clean && bun run build:cli"
12
+ "clean": "rimraf dist",
13
+ "build:js": "bun build ./src/index.ts --outdir ./dist --target bun --packages external --root ./src --minify",
14
+ "build:ts": "tsc",
15
+ "build": "bun run clean && bun run build:js && bun run build:ts",
16
+ "prepublishOnly": "bun run build"
16
17
  },
17
18
  "keywords": [
18
19
  "elysium",
19
20
  "job",
20
21
  "queue",
21
22
  "worker",
23
+ "scheduler",
22
24
  "background",
23
25
  "processing",
24
26
  "heracles"
@@ -26,18 +28,18 @@
26
28
  "author": "Workbud Technologies Inc.",
27
29
  "license": "Apache-2.0",
28
30
  "dependencies": {
29
- "@elysiumjs/core": "latest",
30
31
  "commander": "^13.1.0",
31
32
  "radash": "^12.1.0",
32
33
  "reflect-metadata": "^0.2.2"
33
34
  },
34
35
  "devDependencies": {
35
- "bun-types": "^1.2.13",
36
+ "bun-types": "^1.2.15",
36
37
  "prettier": "^3.5.3",
37
38
  "rimraf": "^6.0.1",
38
39
  "type-fest": "^4.41.0"
39
40
  },
40
41
  "peerDependencies": {
42
+ "@elysiumjs/core": "latest",
41
43
  "typescript": "^5.8.3"
42
44
  }
43
45
  }
package/tsconfig.json CHANGED
@@ -12,36 +12,37 @@
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  {
15
- "compilerOptions": {
16
- // Environment setup & latest features
17
- "target": "ESNext",
18
- "module": "ESNext",
19
- "moduleDetection": "force",
20
- "allowJs": true,
21
- "types": [
22
- "bun-types",
23
- "type-fest"
24
- ],
25
- "experimentalDecorators": true,
26
- "emitDecoratorMetadata": true,
27
- // Bundler mode
28
- "moduleResolution": "bundler",
29
- "allowImportingTsExtensions": true,
30
- "verbatimModuleSyntax": true,
31
- "noEmit": true,
32
- // Best practices
33
- "strict": true,
34
- "skipLibCheck": true,
35
- "noFallthroughCasesInSwitch": true,
36
- "noUncheckedIndexedAccess": false,
37
- "forceConsistentCasingInFileNames": true,
38
- // Some stricter flags (disabled by default)
39
- "noUnusedLocals": true,
40
- "noUnusedParameters": true,
41
- "noPropertyAccessFromIndexSignature": false,
42
- },
43
- "exclude": [
44
- "node_modules",
45
- "dist",
46
- ],
47
- }
15
+ "compilerOptions": {
16
+ // Environment setup & latest features
17
+ "target": "ESNext",
18
+ "module": "ESNext",
19
+ "moduleDetection": "force",
20
+ "allowJs": true,
21
+ "types": ["bun-types", "type-fest"],
22
+ "experimentalDecorators": true,
23
+ "emitDecoratorMetadata": true,
24
+ // Compiler setup
25
+ "outDir": "dist",
26
+ "declaration": true,
27
+ "emitDeclarationOnly": true,
28
+ "declarationMap": false,
29
+ "declarationDir": "dist",
30
+ "rootDir": "src",
31
+ // Bundler mode
32
+ "moduleResolution": "bundler",
33
+ "allowImportingTsExtensions": true,
34
+ "verbatimModuleSyntax": true,
35
+ // Best practices
36
+ "strict": true,
37
+ "skipLibCheck": true,
38
+ "noFallthroughCasesInSwitch": true,
39
+ "noUncheckedIndexedAccess": false,
40
+ "forceConsistentCasingInFileNames": true,
41
+ // Some stricter flags (disabled by default)
42
+ "noUnusedLocals": true,
43
+ "noUnusedParameters": true,
44
+ "noPropertyAccessFromIndexSignature": false
45
+ },
46
+ "exclude": ["node_modules", "dist"],
47
+ "include": ["src"]
48
+ }