nodejs-task-scheduler 1.0.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.
Files changed (50) hide show
  1. package/.claude/settings.local.json +20 -0
  2. package/.github/workflows/ci.yml +266 -0
  3. package/.github/workflows/release.yml +117 -0
  4. package/CHANGELOG.md +43 -0
  5. package/README.md +653 -0
  6. package/dist/__tests__/setup.d.ts +2 -0
  7. package/dist/__tests__/setup.d.ts.map +1 -0
  8. package/dist/__tests__/setup.js +24 -0
  9. package/dist/__tests__/setup.js.map +1 -0
  10. package/dist/decorators/index.d.ts +80 -0
  11. package/dist/decorators/index.d.ts.map +1 -0
  12. package/dist/decorators/index.js +171 -0
  13. package/dist/decorators/index.js.map +1 -0
  14. package/dist/decorators/metadata.d.ts +59 -0
  15. package/dist/decorators/metadata.d.ts.map +1 -0
  16. package/dist/decorators/metadata.js +68 -0
  17. package/dist/decorators/metadata.js.map +1 -0
  18. package/dist/decorators/registry.d.ts +42 -0
  19. package/dist/decorators/registry.d.ts.map +1 -0
  20. package/dist/decorators/registry.js +182 -0
  21. package/dist/decorators/registry.js.map +1 -0
  22. package/dist/index.d.ts +74 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +198 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/queue/index.d.ts +19 -0
  27. package/dist/queue/index.d.ts.map +1 -0
  28. package/dist/queue/index.js +89 -0
  29. package/dist/queue/index.js.map +1 -0
  30. package/dist/scheduler/index.d.ts +13 -0
  31. package/dist/scheduler/index.d.ts.map +1 -0
  32. package/dist/scheduler/index.js +102 -0
  33. package/dist/scheduler/index.js.map +1 -0
  34. package/dist/types/index.d.ts +63 -0
  35. package/dist/types/index.d.ts.map +1 -0
  36. package/dist/types/index.js +12 -0
  37. package/dist/types/index.js.map +1 -0
  38. package/dist/utils/load-balancer.d.ts +36 -0
  39. package/dist/utils/load-balancer.d.ts.map +1 -0
  40. package/dist/utils/load-balancer.js +158 -0
  41. package/dist/utils/load-balancer.js.map +1 -0
  42. package/dist/utils/rabbitmq.d.ts +18 -0
  43. package/dist/utils/rabbitmq.d.ts.map +1 -0
  44. package/dist/utils/rabbitmq.js +114 -0
  45. package/dist/utils/rabbitmq.js.map +1 -0
  46. package/dist/worker/index.d.ts +20 -0
  47. package/dist/worker/index.d.ts.map +1 -0
  48. package/dist/worker/index.js +138 -0
  49. package/dist/worker/index.js.map +1 -0
  50. package/package.json +63 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-balancer.d.ts","sourceRoot":"","sources":["../../src/utils/load-balancer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,aAAa,CAAS;gBAElB,UAAU,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM;IAKpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrB,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5E,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAiBpD,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAetD,WAAW,IAAI,QAAQ,EAAE;IAIzB,cAAc,IAAI,QAAQ,EAAE;IAK5B,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;YAc5C,oBAAoB;YAapB,cAAc;YAQd,aAAa;YAgBb,oBAAoB;YAgBpB,mBAAmB;IAgBjC,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,gBAAgB;CAYzB"}
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoadBalancer = void 0;
4
+ class LoadBalancer {
5
+ constructor(connection, nodeId) {
6
+ this.nodes = new Map();
7
+ this.heartbeatInterval = null;
8
+ this.heartbeatIntervalMs = 30000;
9
+ this.nodeTimeoutMs = 90000;
10
+ this.connection = connection;
11
+ this.nodeId = nodeId;
12
+ }
13
+ async start() {
14
+ await this.setupHeartbeatQueues();
15
+ await this.startHeartbeat();
16
+ await this.listenForHeartbeats();
17
+ console.log(`Load balancer started for node ${this.nodeId}`);
18
+ }
19
+ async stop() {
20
+ if (this.heartbeatInterval) {
21
+ clearInterval(this.heartbeatInterval);
22
+ this.heartbeatInterval = null;
23
+ }
24
+ await this.sendOfflineHeartbeat();
25
+ console.log(`Load balancer stopped for node ${this.nodeId}`);
26
+ }
27
+ async registerNode(nodeInfo) {
28
+ const fullNodeInfo = {
29
+ ...nodeInfo,
30
+ lastHeartbeat: new Date()
31
+ };
32
+ this.nodes.set(nodeInfo.id, fullNodeInfo);
33
+ console.log(`Node ${nodeInfo.id} registered`);
34
+ }
35
+ getAvailableNode(queueName) {
36
+ const availableNodes = Array.from(this.nodes.values())
37
+ .filter(node => node.status === 'active' &&
38
+ node.queues.includes(queueName) &&
39
+ node.activeJobs < node.maxConcurrency &&
40
+ this.isNodeAlive(node))
41
+ .sort((a, b) => {
42
+ const loadA = a.activeJobs / a.maxConcurrency;
43
+ const loadB = b.activeJobs / b.maxConcurrency;
44
+ return loadA - loadB;
45
+ });
46
+ return availableNodes.length > 0 ? availableNodes[0] : null;
47
+ }
48
+ getLeastLoadedNode(queueName) {
49
+ const nodes = Array.from(this.nodes.values())
50
+ .filter(node => node.queues.includes(queueName) &&
51
+ this.isNodeAlive(node))
52
+ .sort((a, b) => {
53
+ const loadA = a.activeJobs / a.maxConcurrency;
54
+ const loadB = b.activeJobs / b.maxConcurrency;
55
+ return loadA - loadB;
56
+ });
57
+ return nodes.length > 0 ? nodes[0] : null;
58
+ }
59
+ getAllNodes() {
60
+ return Array.from(this.nodes.values());
61
+ }
62
+ getActiveNodes() {
63
+ return Array.from(this.nodes.values())
64
+ .filter(node => this.isNodeAlive(node));
65
+ }
66
+ updateNodeStatus(nodeId, activeJobs) {
67
+ const node = this.nodes.get(nodeId);
68
+ if (node) {
69
+ node.activeJobs = activeJobs;
70
+ node.lastHeartbeat = new Date();
71
+ if (activeJobs >= node.maxConcurrency) {
72
+ node.status = 'busy';
73
+ }
74
+ else {
75
+ node.status = 'active';
76
+ }
77
+ }
78
+ }
79
+ async setupHeartbeatQueues() {
80
+ const channel = this.connection.getChannel();
81
+ await channel.assertExchange('heartbeat', 'fanout', { durable: false });
82
+ await channel.assertQueue('heartbeat_queue', {
83
+ durable: false,
84
+ autoDelete: true,
85
+ exclusive: false
86
+ });
87
+ await channel.bindQueue('heartbeat_queue', 'heartbeat', '');
88
+ }
89
+ async startHeartbeat() {
90
+ this.heartbeatInterval = setInterval(async () => {
91
+ await this.sendHeartbeat();
92
+ }, this.heartbeatIntervalMs);
93
+ await this.sendHeartbeat();
94
+ }
95
+ async sendHeartbeat() {
96
+ const channel = this.connection.getChannel();
97
+ const heartbeat = {
98
+ nodeId: this.nodeId,
99
+ timestamp: new Date(),
100
+ status: 'active'
101
+ };
102
+ await channel.publish('heartbeat', '', Buffer.from(JSON.stringify(heartbeat)));
103
+ }
104
+ async sendOfflineHeartbeat() {
105
+ const channel = this.connection.getChannel();
106
+ const heartbeat = {
107
+ nodeId: this.nodeId,
108
+ timestamp: new Date(),
109
+ status: 'offline'
110
+ };
111
+ await channel.publish('heartbeat', '', Buffer.from(JSON.stringify(heartbeat)));
112
+ }
113
+ async listenForHeartbeats() {
114
+ const channel = this.connection.getChannel();
115
+ await channel.consume('heartbeat_queue', (msg) => {
116
+ if (msg) {
117
+ try {
118
+ const heartbeat = JSON.parse(msg.content.toString());
119
+ this.processHeartbeat(heartbeat);
120
+ }
121
+ catch (error) {
122
+ console.error('Error processing heartbeat:', error);
123
+ }
124
+ channel.ack(msg);
125
+ }
126
+ });
127
+ }
128
+ processHeartbeat(heartbeat) {
129
+ const { nodeId, timestamp, status } = heartbeat;
130
+ if (nodeId === this.nodeId) {
131
+ return;
132
+ }
133
+ const node = this.nodes.get(nodeId);
134
+ if (node) {
135
+ node.lastHeartbeat = new Date(timestamp);
136
+ if (status === 'offline') {
137
+ node.status = 'offline';
138
+ }
139
+ }
140
+ }
141
+ isNodeAlive(node) {
142
+ const now = new Date();
143
+ const timeSinceHeartbeat = now.getTime() - node.lastHeartbeat.getTime();
144
+ return timeSinceHeartbeat < this.nodeTimeoutMs && node.status !== 'offline';
145
+ }
146
+ cleanupDeadNodes() {
147
+ const now = new Date();
148
+ for (const [nodeId, node] of this.nodes.entries()) {
149
+ const timeSinceHeartbeat = now.getTime() - node.lastHeartbeat.getTime();
150
+ if (timeSinceHeartbeat > this.nodeTimeoutMs) {
151
+ node.status = 'offline';
152
+ console.log(`Node ${nodeId} marked as offline due to missed heartbeats`);
153
+ }
154
+ }
155
+ }
156
+ }
157
+ exports.LoadBalancer = LoadBalancer;
158
+ //# sourceMappingURL=load-balancer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-balancer.js","sourceRoot":"","sources":["../../src/utils/load-balancer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { ConnectionConfig } from '../types';
2
+ export declare class RabbitMQConnection {
3
+ private connection;
4
+ private channel;
5
+ private config;
6
+ private reconnectAttempts;
7
+ private maxReconnectAttempts;
8
+ private reconnectDelay;
9
+ constructor(config: ConnectionConfig);
10
+ connect(): Promise<void>;
11
+ disconnect(): Promise<void>;
12
+ getChannel(): any;
13
+ isConnected(): boolean;
14
+ private handleConnectionError;
15
+ private handleConnectionClose;
16
+ private handleReconnect;
17
+ }
18
+ //# sourceMappingURL=rabbitmq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq.d.ts","sourceRoot":"","sources":["../../src/utils/rabbitmq.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,oBAAoB,CAAM;IAClC,OAAO,CAAC,cAAc,CAAQ;gBAElB,MAAM,EAAE,gBAAgB;IAI9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBjC,UAAU,IAAI,GAAG;IAOjB,WAAW,IAAI,OAAO;YAIR,qBAAqB;YAKrB,qBAAqB;YAOrB,eAAe;CAY9B"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.RabbitMQConnection = void 0;
37
+ const amqp = __importStar(require("amqplib"));
38
+ class RabbitMQConnection {
39
+ constructor(config) {
40
+ this.connection = null;
41
+ this.channel = null;
42
+ this.reconnectAttempts = 0;
43
+ this.maxReconnectAttempts = 10;
44
+ this.reconnectDelay = 5000;
45
+ this.config = config;
46
+ }
47
+ async connect() {
48
+ try {
49
+ this.connection = await amqp.connect(this.config.url, this.config.options);
50
+ this.channel = await this.connection.createChannel();
51
+ this.connection.on('error', this.handleConnectionError.bind(this));
52
+ this.connection.on('close', this.handleConnectionClose.bind(this));
53
+ this.reconnectAttempts = 0;
54
+ console.log('Connected to RabbitMQ');
55
+ }
56
+ catch (error) {
57
+ console.error('Failed to connect to RabbitMQ:', error);
58
+ await this.handleReconnect();
59
+ }
60
+ }
61
+ async disconnect() {
62
+ try {
63
+ if (this.channel) {
64
+ await this.channel.close();
65
+ this.channel = null;
66
+ }
67
+ }
68
+ catch (error) {
69
+ console.warn('Error closing channel:', error);
70
+ this.channel = null;
71
+ }
72
+ try {
73
+ if (this.connection) {
74
+ await this.connection.close();
75
+ this.connection = null;
76
+ }
77
+ }
78
+ catch (error) {
79
+ console.warn('Error closing connection:', error);
80
+ this.connection = null;
81
+ }
82
+ }
83
+ getChannel() {
84
+ if (!this.channel) {
85
+ throw new Error('Not connected to RabbitMQ');
86
+ }
87
+ return this.channel;
88
+ }
89
+ isConnected() {
90
+ return this.connection !== null && this.channel !== null;
91
+ }
92
+ async handleConnectionError(error) {
93
+ console.error('RabbitMQ connection error:', error);
94
+ await this.handleReconnect();
95
+ }
96
+ async handleConnectionClose() {
97
+ console.log('RabbitMQ connection closed');
98
+ this.connection = null;
99
+ this.channel = null;
100
+ await this.handleReconnect();
101
+ }
102
+ async handleReconnect() {
103
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
104
+ console.error('Max reconnection attempts reached');
105
+ return;
106
+ }
107
+ this.reconnectAttempts++;
108
+ console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
109
+ await new Promise(resolve => setTimeout(resolve, this.reconnectDelay));
110
+ await this.connect();
111
+ }
112
+ }
113
+ exports.RabbitMQConnection = RabbitMQConnection;
114
+ //# sourceMappingURL=rabbitmq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq.js","sourceRoot":"","sources":["../../src/utils/rabbitmq.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { WorkerConfig } from '../types';
2
+ import { RabbitMQConnection } from '../utils/rabbitmq';
3
+ export declare class JobWorker {
4
+ private connection;
5
+ private config;
6
+ private isRunning;
7
+ private activeJobs;
8
+ constructor(connection: RabbitMQConnection, config: WorkerConfig);
9
+ start(): Promise<void>;
10
+ stop(): Promise<void>;
11
+ private processMessage;
12
+ private handleJobError;
13
+ private shouldSkipJob;
14
+ private calculateBackoffDelay;
15
+ private scheduleRetry;
16
+ private sendToDeadLetterQueue;
17
+ getActiveJobCount(): number;
18
+ isWorkerRunning(): boolean;
19
+ }
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAoC,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,qBAAa,SAAS;IACpB,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAqB;gBAE3B,UAAU,EAAE,kBAAkB,EAAE,MAAM,EAAE,YAAY;IAK1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAWb,cAAc;YA2Cd,cAAc;IAuB5B,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,qBAAqB;YAaf,aAAa;YAab,qBAAqB;IAYnC,iBAAiB,IAAI,MAAM;IAI3B,eAAe,IAAI,OAAO;CAG3B"}
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JobWorker = void 0;
4
+ const types_1 = require("../types");
5
+ class JobWorker {
6
+ constructor(connection, config) {
7
+ this.isRunning = false;
8
+ this.activeJobs = new Set();
9
+ this.connection = connection;
10
+ this.config = config;
11
+ }
12
+ async start() {
13
+ if (this.isRunning) {
14
+ throw new Error('Worker is already running');
15
+ }
16
+ const channel = this.connection.getChannel();
17
+ for (const queueName of this.config.queues) {
18
+ await channel.assertQueue(queueName, { durable: true });
19
+ await channel.prefetch(this.config.concurrency);
20
+ await channel.consume(queueName, async (msg) => {
21
+ if (msg) {
22
+ await this.processMessage(msg, queueName);
23
+ }
24
+ });
25
+ }
26
+ this.isRunning = true;
27
+ console.log(`Worker ${this.config.name} started with concurrency ${this.config.concurrency}`);
28
+ }
29
+ async stop() {
30
+ this.isRunning = false;
31
+ while (this.activeJobs.size > 0) {
32
+ console.log(`Waiting for ${this.activeJobs.size} active jobs to complete...`);
33
+ await new Promise(resolve => setTimeout(resolve, 1000));
34
+ }
35
+ console.log(`Worker ${this.config.name} stopped`);
36
+ }
37
+ async processMessage(msg, queueName) {
38
+ const channel = this.connection.getChannel();
39
+ try {
40
+ const jobMessage = JSON.parse(msg.content.toString());
41
+ if (this.shouldSkipJob(jobMessage)) {
42
+ channel.ack(msg);
43
+ return;
44
+ }
45
+ this.activeJobs.add(jobMessage.id);
46
+ jobMessage.status = types_1.JobStatus.PROCESSING;
47
+ jobMessage.processedAt = new Date();
48
+ jobMessage.attempts++;
49
+ console.log(`Processing job ${jobMessage.id} (attempt ${jobMessage.attempts})`);
50
+ const handler = this.config.handlers[jobMessage.config.handler];
51
+ if (!handler) {
52
+ throw new Error(`No handler found for job type: ${jobMessage.config.handler}`);
53
+ }
54
+ const result = await handler(jobMessage.config.data);
55
+ if (result.success) {
56
+ jobMessage.status = types_1.JobStatus.COMPLETED;
57
+ jobMessage.completedAt = new Date();
58
+ console.log(`Job ${jobMessage.id} completed successfully`);
59
+ channel.ack(msg);
60
+ }
61
+ else {
62
+ throw new Error(result.error || 'Job failed without error message');
63
+ }
64
+ }
65
+ catch (error) {
66
+ await this.handleJobError(msg, error, queueName);
67
+ }
68
+ finally {
69
+ const jobMessage = JSON.parse(msg.content.toString());
70
+ this.activeJobs.delete(jobMessage.id);
71
+ }
72
+ }
73
+ async handleJobError(msg, error, queueName) {
74
+ const channel = this.connection.getChannel();
75
+ const jobMessage = JSON.parse(msg.content.toString());
76
+ jobMessage.error = error.message;
77
+ const maxAttempts = jobMessage.config.attempts || 3;
78
+ if (jobMessage.attempts >= maxAttempts) {
79
+ jobMessage.status = types_1.JobStatus.FAILED;
80
+ console.error(`Job ${jobMessage.id} failed permanently after ${jobMessage.attempts} attempts:`, error.message);
81
+ await this.sendToDeadLetterQueue(jobMessage);
82
+ channel.ack(msg);
83
+ }
84
+ else {
85
+ jobMessage.status = types_1.JobStatus.RETRY;
86
+ console.log(`Job ${jobMessage.id} will be retried (attempt ${jobMessage.attempts + 1}/${maxAttempts})`);
87
+ const delay = this.calculateBackoffDelay(jobMessage);
88
+ await this.scheduleRetry(jobMessage, delay);
89
+ channel.ack(msg);
90
+ }
91
+ }
92
+ shouldSkipJob(jobMessage) {
93
+ if (this.config.concurrency === 1 && this.activeJobs.size > 0) {
94
+ return true;
95
+ }
96
+ if (this.activeJobs.size >= this.config.concurrency) {
97
+ return true;
98
+ }
99
+ return false;
100
+ }
101
+ calculateBackoffDelay(jobMessage) {
102
+ const backoff = jobMessage.config.backoff;
103
+ if (!backoff) {
104
+ return 5000;
105
+ }
106
+ if (backoff.type === 'exponential') {
107
+ return backoff.delay * Math.pow(2, jobMessage.attempts - 1);
108
+ }
109
+ return backoff.delay;
110
+ }
111
+ async scheduleRetry(jobMessage, delay) {
112
+ setTimeout(async () => {
113
+ const channel = this.connection.getChannel();
114
+ const queueName = `job_queue_${jobMessage.config.handler}`;
115
+ const message = Buffer.from(JSON.stringify(jobMessage));
116
+ await channel.sendToQueue(queueName, message, {
117
+ persistent: true,
118
+ priority: jobMessage.config.priority || 0
119
+ });
120
+ }, delay);
121
+ }
122
+ async sendToDeadLetterQueue(jobMessage) {
123
+ const channel = this.connection.getChannel();
124
+ const deadLetterQueue = 'dead_letter_queue';
125
+ await channel.assertQueue(deadLetterQueue, { durable: true });
126
+ const message = Buffer.from(JSON.stringify(jobMessage));
127
+ await channel.sendToQueue(deadLetterQueue, message, { persistent: true });
128
+ console.log(`Job ${jobMessage.id} sent to dead letter queue`);
129
+ }
130
+ getActiveJobCount() {
131
+ return this.activeJobs.size;
132
+ }
133
+ isWorkerRunning() {
134
+ return this.isRunning;
135
+ }
136
+ }
137
+ exports.JobWorker = JobWorker;
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "nodejs-task-scheduler",
3
+ "version": "1.0.0",
4
+ "description": "Distributed task scheduler using RabbitMQ with cron and direct job execution",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "node dist/index.js",
10
+ "dev": "ts-node src/index.ts",
11
+ "test": "jest",
12
+ "lint": "eslint src/**/*.ts --fix",
13
+ "typecheck": "tsc --noEmit",
14
+ "clean": "rm -rf dist",
15
+ "prepack": "npm run clean && npm run build",
16
+ "prepublishOnly": "npm run test && npm run lint && npm run typecheck",
17
+ "docker:build": "docker build -t nodejs-task-scheduler .",
18
+ "docker:run": "docker-compose up -d",
19
+ "docker:stop": "docker-compose down",
20
+ "docker:logs": "docker-compose logs -f"
21
+ },
22
+ "keywords": [
23
+ "task",
24
+ "scheduler",
25
+ "rabbitmq",
26
+ "cron",
27
+ "distributed",
28
+ "queue"
29
+ ],
30
+ "author": "Ruben de Roos",
31
+ "homepage": "https://github.com/thedutchruben/nodejs-task-scheduler#readme",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/thedutchruben/nodejs-task-scheduler.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/thedutchruben/nodejs-task-scheduler/issues"
38
+ },
39
+ "license": "MIT",
40
+ "engines": {
41
+ "node": ">=16.0.0"
42
+ },
43
+ "dependencies": {
44
+ "amqplib": "^0.10.3",
45
+ "node-cron": "^3.0.3",
46
+ "reflect-metadata": "^0.1.13",
47
+ "uuid": "^9.0.1"
48
+ },
49
+ "devDependencies": {
50
+ "@types/amqplib": "^0.10.7",
51
+ "@types/jest": "^29.5.8",
52
+ "@types/node": "^20.10.0",
53
+ "@types/node-cron": "^3.0.11",
54
+ "@types/uuid": "^9.0.7",
55
+ "@typescript-eslint/eslint-plugin": "^6.13.0",
56
+ "@typescript-eslint/parser": "^6.13.0",
57
+ "eslint": "^8.55.0",
58
+ "jest": "^29.7.0",
59
+ "ts-jest": "^29.1.1",
60
+ "ts-node": "^10.9.1",
61
+ "typescript": "^5.3.2"
62
+ }
63
+ }