@platformatic/job-queue 0.0.1 → 0.1.0-alpha.3

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.
Files changed (58) hide show
  1. package/README.md +511 -0
  2. package/dist/consumer.d.ts +43 -0
  3. package/dist/consumer.d.ts.map +1 -0
  4. package/dist/consumer.js +214 -0
  5. package/dist/consumer.js.map +1 -0
  6. package/dist/errors.d.ts +60 -0
  7. package/dist/errors.d.ts.map +1 -0
  8. package/dist/errors.js +141 -0
  9. package/dist/errors.js.map +1 -0
  10. package/dist/index.d.ts +12 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +13 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/producer.d.ts +39 -0
  15. package/dist/producer.d.ts.map +1 -0
  16. package/dist/producer.js +163 -0
  17. package/dist/producer.js.map +1 -0
  18. package/dist/queue.d.ts +42 -0
  19. package/dist/queue.d.ts.map +1 -0
  20. package/dist/queue.js +153 -0
  21. package/dist/queue.js.map +1 -0
  22. package/dist/reaper.d.ts +52 -0
  23. package/dist/reaper.d.ts.map +1 -0
  24. package/dist/reaper.js +376 -0
  25. package/dist/reaper.js.map +1 -0
  26. package/dist/serde/index.d.ts +19 -0
  27. package/dist/serde/index.d.ts.map +1 -0
  28. package/dist/serde/index.js +18 -0
  29. package/dist/serde/index.js.map +1 -0
  30. package/dist/storage/file.d.ts +44 -0
  31. package/dist/storage/file.d.ts.map +1 -0
  32. package/dist/storage/file.js +601 -0
  33. package/dist/storage/file.js.map +1 -0
  34. package/dist/storage/memory.d.ts +39 -0
  35. package/dist/storage/memory.d.ts.map +1 -0
  36. package/dist/storage/memory.js +292 -0
  37. package/dist/storage/memory.js.map +1 -0
  38. package/dist/storage/redis.d.ts +47 -0
  39. package/dist/storage/redis.d.ts.map +1 -0
  40. package/dist/storage/redis.js +317 -0
  41. package/dist/storage/redis.js.map +1 -0
  42. package/dist/storage/types.d.ts +179 -0
  43. package/dist/storage/types.d.ts.map +1 -0
  44. package/dist/storage/types.js +2 -0
  45. package/dist/storage/types.js.map +1 -0
  46. package/dist/types.d.ts +126 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/utils/id.d.ts +10 -0
  51. package/dist/utils/id.d.ts.map +1 -0
  52. package/dist/utils/id.js +18 -0
  53. package/dist/utils/id.js.map +1 -0
  54. package/dist/utils/state.d.ts +13 -0
  55. package/dist/utils/state.d.ts.map +1 -0
  56. package/dist/utils/state.js +22 -0
  57. package/dist/utils/state.js.map +1 -0
  58. package/package.json +45 -9
@@ -0,0 +1,163 @@
1
+ import { TimeoutError, JobFailedError } from "./errors.js";
2
+ import { createJsonSerde } from "./serde/index.js";
3
+ import { parseState } from "./utils/state.js";
4
+ /**
5
+ * Producer handles enqueueing jobs and retrieving results
6
+ */
7
+ export class Producer {
8
+ #storage;
9
+ #payloadSerde;
10
+ #resultSerde;
11
+ #maxRetries;
12
+ #resultTTL;
13
+ constructor(config) {
14
+ this.#storage = config.storage;
15
+ this.#payloadSerde = config.payloadSerde ?? createJsonSerde();
16
+ this.#resultSerde = config.resultSerde ?? createJsonSerde();
17
+ this.#maxRetries = config.maxRetries ?? 3;
18
+ this.#resultTTL = config.resultTTL ?? 3600000; // 1 hour
19
+ }
20
+ /**
21
+ * Enqueue a job (fire-and-forget)
22
+ */
23
+ async enqueue(id, payload, options) {
24
+ const timestamp = Date.now();
25
+ const maxAttempts = options?.maxAttempts ?? this.#maxRetries;
26
+ const message = {
27
+ id,
28
+ payload,
29
+ createdAt: timestamp,
30
+ attempts: 0,
31
+ maxAttempts
32
+ };
33
+ const serialized = this.#payloadSerde.serialize(message);
34
+ const existingState = await this.#storage.enqueue(id, serialized, timestamp);
35
+ if (existingState) {
36
+ const { status } = parseState(existingState);
37
+ if (status === 'completed') {
38
+ const result = await this.getResult(id);
39
+ if (result !== null) {
40
+ return { status: 'completed', result };
41
+ }
42
+ }
43
+ return { status: 'duplicate', existingState: status };
44
+ }
45
+ return { status: 'queued' };
46
+ }
47
+ /**
48
+ * Enqueue a job and wait for the result
49
+ */
50
+ async enqueueAndWait(id, payload, options) {
51
+ const timeout = options?.timeout ?? 30000;
52
+ // Subscribe BEFORE enqueue to avoid race conditions
53
+ const { promise: resultPromise, resolve: resolveResult, reject: rejectResult } = Promise.withResolvers();
54
+ const unsubscribe = await this.#storage.subscribeToJob(id, async (status) => {
55
+ if (status === 'completed') {
56
+ const result = await this.getResult(id);
57
+ if (result !== null) {
58
+ resolveResult(result);
59
+ }
60
+ }
61
+ else if (status === 'failed') {
62
+ const error = await this.#storage.getError(id);
63
+ const errorMessage = error ? error.toString() : 'Job failed';
64
+ rejectResult(new JobFailedError(id, errorMessage));
65
+ }
66
+ });
67
+ let timeoutId;
68
+ try {
69
+ // Now enqueue
70
+ const enqueueResult = await this.enqueue(id, payload, options);
71
+ // If already completed, return cached result immediately
72
+ if (enqueueResult.status === 'completed') {
73
+ return enqueueResult.result;
74
+ }
75
+ // If duplicate and already failed, throw immediately
76
+ if (enqueueResult.status === 'duplicate' && enqueueResult.existingState === 'failed') {
77
+ const error = await this.#storage.getError(id);
78
+ const errorMessage = error ? error.toString() : 'Job failed';
79
+ throw new JobFailedError(id, errorMessage);
80
+ }
81
+ // Wait for result with timeout
82
+ const { promise: timeoutPromise, reject: rejectTimeout } = Promise.withResolvers();
83
+ timeoutId = setTimeout(() => {
84
+ rejectTimeout(new TimeoutError(id, timeout));
85
+ }, timeout);
86
+ return await Promise.race([resultPromise, timeoutPromise]);
87
+ }
88
+ finally {
89
+ if (timeoutId !== undefined) {
90
+ clearTimeout(timeoutId);
91
+ }
92
+ await unsubscribe();
93
+ }
94
+ }
95
+ /**
96
+ * Cancel a pending job
97
+ */
98
+ async cancel(id) {
99
+ const state = await this.#storage.getJobState(id);
100
+ if (!state) {
101
+ return { status: 'not_found' };
102
+ }
103
+ const { status } = parseState(state);
104
+ if (status === 'completed') {
105
+ return { status: 'completed' };
106
+ }
107
+ if (status === 'processing') {
108
+ return { status: 'processing' };
109
+ }
110
+ // Can cancel if queued or failing
111
+ const deleted = await this.#storage.deleteJob(id);
112
+ if (deleted) {
113
+ return { status: 'cancelled' };
114
+ }
115
+ return { status: 'not_found' };
116
+ }
117
+ /**
118
+ * Get the result of a completed job
119
+ */
120
+ async getResult(id) {
121
+ const resultBuffer = await this.#storage.getResult(id);
122
+ if (!resultBuffer) {
123
+ return null;
124
+ }
125
+ return this.#resultSerde.deserialize(resultBuffer);
126
+ }
127
+ /**
128
+ * Get the status of a job
129
+ */
130
+ async getStatus(id) {
131
+ const state = await this.#storage.getJobState(id);
132
+ if (!state) {
133
+ return null;
134
+ }
135
+ const { status, timestamp } = parseState(state);
136
+ const messageStatus = {
137
+ id,
138
+ state: status,
139
+ createdAt: timestamp,
140
+ attempts: 0
141
+ };
142
+ if (status === 'completed') {
143
+ const result = await this.getResult(id);
144
+ if (result !== null) {
145
+ messageStatus.result = result;
146
+ }
147
+ }
148
+ else if (status === 'failed') {
149
+ const errorBuffer = await this.#storage.getError(id);
150
+ if (errorBuffer) {
151
+ try {
152
+ messageStatus.error = JSON.parse(errorBuffer.toString());
153
+ }
154
+ catch {
155
+ // Fallback for non-JSON errors
156
+ messageStatus.error = { message: errorBuffer.toString() };
157
+ }
158
+ }
159
+ }
160
+ return messageStatus;
161
+ }
162
+ }
163
+ //# sourceMappingURL=producer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"producer.js","sourceRoot":"","sources":["../src/producer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { QueueConfig, EnqueueOptions, EnqueueAndWaitOptions, EnqueueResult, CancelResult, MessageStatus, JobHandler, QueueEvents } from './types.ts';
3
+ /**
4
+ * Queue class combining Producer and Consumer functionality
5
+ */
6
+ export declare class Queue<TPayload, TResult = void> extends EventEmitter<QueueEvents<TResult>> {
7
+ #private;
8
+ constructor(config: QueueConfig<TPayload, TResult>);
9
+ /**
10
+ * Start the queue (connects storage and starts consumer if handler registered)
11
+ */
12
+ start(): Promise<void>;
13
+ /**
14
+ * Stop the queue gracefully
15
+ */
16
+ stop(): Promise<void>;
17
+ /**
18
+ * Register a job handler (makes this queue a consumer)
19
+ */
20
+ execute(handler: JobHandler<TPayload, TResult>): void;
21
+ /**
22
+ * Enqueue a job (fire-and-forget)
23
+ */
24
+ enqueue(id: string, payload: TPayload, options?: EnqueueOptions): Promise<EnqueueResult<TResult>>;
25
+ /**
26
+ * Enqueue a job and wait for the result
27
+ */
28
+ enqueueAndWait(id: string, payload: TPayload, options?: EnqueueAndWaitOptions): Promise<TResult>;
29
+ /**
30
+ * Cancel a pending job
31
+ */
32
+ cancel(id: string): Promise<CancelResult>;
33
+ /**
34
+ * Get the result of a completed job
35
+ */
36
+ getResult(id: string): Promise<TResult | null>;
37
+ /**
38
+ * Get the status of a job
39
+ */
40
+ getStatus(id: string): Promise<MessageStatus<TResult> | null>;
41
+ }
42
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAI1C,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,UAAU,EACV,WAAW,EACZ,MAAM,YAAY,CAAA;AAKnB;;GAEG;AACH,qBAAa,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAE,SAAQ,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;;gBAgBxE,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC;IAsBnD;;OAEG;IACG,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAc7B;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;IAa5B;;OAEG;IACH,OAAO,CAAE,OAAO,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,IAAI;IAStD;;OAEG;IACG,OAAO,CACX,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAQlC;;OAEG;IACG,cAAc,CAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,OAAO,CAAC;IAInB;;OAEG;IACG,MAAM,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAQhD;;OAEG;IACG,SAAS,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAIrD;;OAEG;IACG,SAAS,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CA6CrE"}
package/dist/queue.js ADDED
@@ -0,0 +1,153 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { Producer } from "./producer.js";
4
+ import { Consumer } from "./consumer.js";
5
+ import { createJsonSerde } from "./serde/index.js";
6
+ /**
7
+ * Queue class combining Producer and Consumer functionality
8
+ */
9
+ export class Queue extends EventEmitter {
10
+ #storage;
11
+ #producer;
12
+ #consumer = null;
13
+ #workerId;
14
+ #handler = null;
15
+ #started = false;
16
+ #payloadSerde;
17
+ #resultSerde;
18
+ #concurrency;
19
+ #blockTimeout;
20
+ #maxRetries;
21
+ #resultTTL;
22
+ #visibilityTimeout;
23
+ constructor(config) {
24
+ super();
25
+ this.#storage = config.storage;
26
+ this.#workerId = config.workerId ?? randomUUID();
27
+ this.#payloadSerde = config.payloadSerde ?? createJsonSerde();
28
+ this.#resultSerde = config.resultSerde ?? createJsonSerde();
29
+ this.#concurrency = config.concurrency ?? 1;
30
+ this.#blockTimeout = config.blockTimeout ?? 5;
31
+ this.#maxRetries = config.maxRetries ?? 3;
32
+ this.#resultTTL = config.resultTTL ?? 3600000;
33
+ this.#visibilityTimeout = config.visibilityTimeout ?? 30000;
34
+ this.#producer = new Producer({
35
+ storage: this.#storage,
36
+ payloadSerde: this.#payloadSerde,
37
+ resultSerde: this.#resultSerde,
38
+ maxRetries: this.#maxRetries,
39
+ resultTTL: this.#resultTTL
40
+ });
41
+ }
42
+ /**
43
+ * Start the queue (connects storage and starts consumer if handler registered)
44
+ */
45
+ async start() {
46
+ if (this.#started)
47
+ return;
48
+ await this.#storage.connect();
49
+ this.#started = true;
50
+ // If handler was registered, start consumer
51
+ if (this.#handler) {
52
+ this.#startConsumer();
53
+ }
54
+ this.emit('started');
55
+ }
56
+ /**
57
+ * Stop the queue gracefully
58
+ */
59
+ async stop() {
60
+ if (!this.#started)
61
+ return;
62
+ if (this.#consumer) {
63
+ await this.#consumer.stop();
64
+ }
65
+ await this.#storage.disconnect();
66
+ this.#started = false;
67
+ this.emit('stopped');
68
+ }
69
+ /**
70
+ * Register a job handler (makes this queue a consumer)
71
+ */
72
+ execute(handler) {
73
+ this.#handler = handler;
74
+ // If already started, create and start consumer
75
+ if (this.#started) {
76
+ this.#startConsumer();
77
+ }
78
+ }
79
+ /**
80
+ * Enqueue a job (fire-and-forget)
81
+ */
82
+ async enqueue(id, payload, options) {
83
+ const result = await this.#producer.enqueue(id, payload, options);
84
+ if (result.status === 'queued') {
85
+ this.emit('enqueued', id);
86
+ }
87
+ return result;
88
+ }
89
+ /**
90
+ * Enqueue a job and wait for the result
91
+ */
92
+ async enqueueAndWait(id, payload, options) {
93
+ return this.#producer.enqueueAndWait(id, payload, options);
94
+ }
95
+ /**
96
+ * Cancel a pending job
97
+ */
98
+ async cancel(id) {
99
+ const result = await this.#producer.cancel(id);
100
+ if (result.status === 'cancelled') {
101
+ this.emit('cancelled', id);
102
+ }
103
+ return result;
104
+ }
105
+ /**
106
+ * Get the result of a completed job
107
+ */
108
+ async getResult(id) {
109
+ return this.#producer.getResult(id);
110
+ }
111
+ /**
112
+ * Get the status of a job
113
+ */
114
+ async getStatus(id) {
115
+ return this.#producer.getStatus(id);
116
+ }
117
+ #startConsumer() {
118
+ if (this.#consumer || !this.#handler)
119
+ return;
120
+ this.#consumer = new Consumer({
121
+ storage: this.#storage,
122
+ workerId: this.#workerId,
123
+ payloadSerde: this.#payloadSerde,
124
+ resultSerde: this.#resultSerde,
125
+ concurrency: this.#concurrency,
126
+ blockTimeout: this.#blockTimeout,
127
+ maxRetries: this.#maxRetries,
128
+ resultTTL: this.#resultTTL,
129
+ visibilityTimeout: this.#visibilityTimeout
130
+ });
131
+ // Forward consumer events
132
+ this.#consumer.on('error', (error) => {
133
+ this.emit('error', error);
134
+ });
135
+ this.#consumer.on('completed', (id, result) => {
136
+ this.emit('completed', id, result);
137
+ });
138
+ this.#consumer.on('failed', (id, error) => {
139
+ this.emit('failed', id, error);
140
+ });
141
+ this.#consumer.on('failing', (id, error, attempt) => {
142
+ this.emit('failing', id, error, attempt);
143
+ });
144
+ this.#consumer.on('requeued', (id) => {
145
+ this.emit('requeued', id);
146
+ });
147
+ this.#consumer.execute(this.#handler);
148
+ this.#consumer.start().catch((err) => {
149
+ this.emit('error', err);
150
+ });
151
+ }
152
+ }
153
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { Storage } from './storage/types.ts';
3
+ import type { Serde } from './serde/index.ts';
4
+ interface LeaderElectionConfig {
5
+ enabled: boolean;
6
+ lockTTL?: number;
7
+ renewalInterval?: number;
8
+ acquireRetryInterval?: number;
9
+ }
10
+ interface ReaperConfig<TPayload> {
11
+ storage: Storage;
12
+ payloadSerde?: Serde<TPayload>;
13
+ visibilityTimeout?: number;
14
+ leaderElection?: LeaderElectionConfig;
15
+ }
16
+ interface ReaperEvents {
17
+ error: [error: Error];
18
+ stalled: [id: string];
19
+ leadershipAcquired: [];
20
+ leadershipLost: [];
21
+ }
22
+ /**
23
+ * Reaper monitors for stalled jobs and requeues them.
24
+ *
25
+ * A job is considered stalled if it has been in "processing" state
26
+ * longer than the visibility timeout.
27
+ *
28
+ * When leader election is enabled, multiple Reaper instances can run
29
+ * for high availability, with only one active at a time.
30
+ */
31
+ export declare class Reaper<TPayload> extends EventEmitter<ReaperEvents> {
32
+ #private;
33
+ constructor(config: ReaperConfig<TPayload>);
34
+ /**
35
+ * Get the unique identifier for this reaper instance
36
+ */
37
+ get reaperId(): string;
38
+ /**
39
+ * Check if this reaper is currently the leader
40
+ */
41
+ get isLeader(): boolean;
42
+ /**
43
+ * Start the reaper
44
+ */
45
+ start(): Promise<void>;
46
+ /**
47
+ * Stop the reaper gracefully
48
+ */
49
+ stop(): Promise<void>;
50
+ }
51
+ export {};
52
+ //# sourceMappingURL=reaper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reaper.d.ts","sourceRoot":"","sources":["../src/reaper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAK7C,UAAU,oBAAoB;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,UAAU,YAAY,CAAC,QAAQ;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,oBAAoB,CAAA;CACtC;AAED,UAAU,YAAY;IACpB,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IACrB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IACrB,kBAAkB,EAAE,EAAE,CAAA;IACtB,cAAc,EAAE,EAAE,CAAA;CACnB;AAOD;;;;;;;;GAQG;AACH,qBAAa,MAAM,CAAC,QAAQ,CAAE,SAAQ,YAAY,CAAC,YAAY,CAAC;;gBAejD,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC;IAS3C;;OAEG;IACH,IAAI,QAAQ,IAAK,MAAM,CAEtB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAK,OAAO,CAEvB;IAED;;OAEG;IACG,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAa7B;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;CA4V7B"}