redis-smq 8.0.0-rc.15 → 8.0.0-rc.17

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/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
 
2
2
 
3
+ ## [8.0.0-rc.17](https://github.com/weyoss/redis-smq/compare/v8.0.0-rc.16...v8.0.0-rc.17) (2024-01-30)
4
+
5
+
6
+ ### Documentation
7
+
8
+ * add missing error classes ([753331e](https://github.com/weyoss/redis-smq/commit/753331e5ce4fb239cb29b3ae4c3246ba185b4d94))
9
+ * simplify and unify class/method naming and referencing ([0299b31](https://github.com/weyoss/redis-smq/commit/0299b314e843c28d52e2f767ace150e39652287c))
10
+
11
+
12
+ ### Codebase Refactoring
13
+
14
+ * improve MessageHandler error handling ([957d257](https://github.com/weyoss/redis-smq/commit/957d257e66cce6faaf9dad5bf949cdd1198cfae8))
15
+
16
+ ## [8.0.0-rc.16](https://github.com/weyoss/redis-smq/compare/v8.0.0-rc.15...v8.0.0-rc.16) (2024-01-28)
17
+
18
+
19
+ ### Features
20
+
21
+ * allow running/sandboxing message handlers using worker threads ([53095bd](https://github.com/weyoss/redis-smq/commit/53095bd2689ccb2f701365bafb4ef8e550da82b3))
22
+
23
+
24
+ ### Bug Fixes
25
+
26
+ * export message handler errors ([26d2689](https://github.com/weyoss/redis-smq/commit/26d26890da139d88c46ce220e3dda3d9c8e03aee))
27
+
28
+
29
+ ### Documentation
30
+
31
+ * **ConsumeMessageWorker:** update docs and clean up ([140322e](https://github.com/weyoss/redis-smq/commit/140322e3520ee3db905ea977a159064f339aa7d2))
32
+ * fix broken links ([aad9010](https://github.com/weyoss/redis-smq/commit/aad9010e70ed332b154f4fbdcb8ac657a14fe6b9))
33
+ * update messages and queues documentation ([7c3d06e](https://github.com/weyoss/redis-smq/commit/7c3d06ed3765ffc14dfece4f725241aa4535e1e7))
34
+
35
+
36
+ ### Codebase Refactoring
37
+
38
+ * **ConsumeMessageWorker:** improve typings ([66c6ca9](https://github.com/weyoss/redis-smq/commit/66c6ca948677f76d496fe0b988bd195e1a7108a2))
39
+
40
+
41
+ ### Tests
42
+
43
+ * allow running/sandboxing message handlers using worker threads ([79e6886](https://github.com/weyoss/redis-smq/commit/79e688674ed11ec34ce2f74d5f15c8eefa129767))
44
+
3
45
  ## [8.0.0-rc.15](https://github.com/weyoss/redis-smq/compare/v8.0.0-rc.14...v8.0.0-rc.15) (2024-01-25)
4
46
 
5
47
 
package/README.md CHANGED
@@ -27,6 +27,7 @@ RedisSMQ is a Node.js library for queuing messages (aka jobs) and processing the
27
27
  * Supports [Point-2-Point](docs/queue-delivery-models.md#point-2-point-delivery-model) and [Pub/Sub](docs/queue-delivery-models.md#pubsub-delivery-model) [delivery models](docs/queue-delivery-models.md).
28
28
  * Both [delivery models](docs/queue-delivery-models.md) are reliable. For cases of failure, while delivering/consuming messages, [at-least-once](docs/api/classes/ProducibleMessage.md#setretrythreshold) and [at-most-once](docs/api/classes/ProducibleMessage.md#setretrythreshold) modes may be configured.
29
29
  * [3 queuing strategies](docs/queues.md): [FIFO queues](docs/queues.md#fifo-first-in-first-out-queues), [LIFO queues](docs/queues.md#lifo-last-in-first-out-queues), and [Priority Queues](docs/queues.md#priority-queues).
30
+ * [Message Handler Worker Threads](docs/message-handler-worker-threads.md) which allow sandboxing and running your message handler from a separate isolated thread and without affecting the performance of other message handlers from the same consumer.
30
31
  * Messages can be [set to expire](docs/api/classes/ProducibleMessage.md#setttl) when not delivered within a given amount of time or to have a [consumption timeout](docs/api/classes/ProducibleMessage.md#setconsumetimeout) while being in process.
31
32
  * Queues may be [rate Limited](docs/queue-rate-limiting.md) to control the rate at which the messages are consumed.
32
33
  * Has a builtin [scheduler](docs/scheduling-messages.md) allowing messages [to be delayed](docs/api/classes/ProducibleMessage.md#setscheduleddelay), [to be delivered for N times](docs/api/classes/ProducibleMessage.md#setscheduledrepeat) with an optional [period between deliveries](docs/api/classes/ProducibleMessage.md#setscheduledrepeatperiod), or simply [to be scheduled using CRON expressions](docs/api/classes/ProducibleMessage.md#setscheduledcron).
@@ -66,42 +67,44 @@ A queue is responsible for holding messages which are produced by producers and
66
67
  ### Creating a queue
67
68
 
68
69
  ```javascript
69
- const { Queue, EQueueType, EQueueDeliveryModel } = require('redis-smq');
70
-
71
70
  const queue = new Queue();
72
-
73
- // Creating a LIFO queue
74
- queue.save('my_queue', EQueueType.LIFO_QUEUE, EQueueDeliveryModel.POINT_TO_POINT, (err) => console.log(err));
71
+ queue.save('my_queue', EQueueType.LIFO_QUEUE, EQueueDeliveryModel.POINT_TO_POINT, (err) => {
72
+ if (err) console.error(err)
73
+ });
75
74
  ```
76
75
 
77
76
  In the example above we are defining a [LIFO queue](docs/queues.md#lifo-last-in-first-out-queues) with a [POINT-2-POINT delivery model](docs/queue-delivery-models.md#point-2-point-delivery-model).
78
77
 
78
+ See [Queues](docs/queues.md) for more details.
79
+
79
80
  ### Producing a message
80
81
 
81
82
  ```javascript
82
- const { Producer, ProducibleMessage } = require('redis-smq');
83
-
84
- const producer = new Producer();
85
-
86
83
  const msg = new ProducibleMessage();
87
84
  msg.setQueue('my_queue').setBody('Hello Word!')
88
-
89
- producer.produce(msg, (err) => console.log(err));
85
+ producer.produce(msg, (err, ids) => {
86
+ if (err) console.error(err);
87
+ else console.log(`Produced message IDs are: ${ids.join(', ')}`)
88
+ });
90
89
  ```
91
90
 
91
+ See [Producing Messages](docs/producing-messages.md) for more details.
92
+
92
93
  ### Consuming a message
93
94
 
94
95
  ```javascript
95
- const { Consumer } = require('redis-smq');
96
-
97
96
  const consumer = new Consumer();
98
97
  const messageHandler = (msg, cb) => {
99
- console.log(msg.getBody());
98
+ console.log(msg.body);
100
99
  cb();
101
100
  }
102
- consumer.consume('my_queue', messageHandler, (err) => console.log(err));
101
+ consumer.consume('my_queue', messageHandler, (err) => {
102
+ if (err) console.error(err);
103
+ });
103
104
  ```
104
105
 
106
+ See [Consuming Messages](docs/consuming-messages.md) for more details.
107
+
105
108
  ## Documentation
106
109
 
107
110
  See [RedisSMQ Docs](docs/README.md) for more details.
package/dist/index.cjs CHANGED
@@ -69,6 +69,10 @@ __export(redis_smq_exports, {
69
69
  ConsumerGroups: () => ConsumerGroups,
70
70
  ConsumerInvalidGroupIdError: () => ConsumerInvalidGroupIdError,
71
71
  ConsumerMessageHandlerAlreadyExistsError: () => ConsumerMessageHandlerAlreadyExistsError,
72
+ ConsumerMessageHandlerError: () => ConsumerMessageHandlerError,
73
+ ConsumerMessageHandlerFileError: () => ConsumerMessageHandlerFileError,
74
+ ConsumerMessageHandlerFilenameExtensionError: () => ConsumerMessageHandlerFilenameExtensionError,
75
+ ConsumerMessageHandlerWorkerError: () => ConsumerMessageHandlerWorkerError,
72
76
  EConsumeMessageDeadLetterCause: () => EConsumeMessageDeadLetterCause,
73
77
  EConsumeMessageUnacknowledgedCause: () => EConsumeMessageUnacknowledgedCause,
74
78
  EExchangeType: () => EExchangeType,
@@ -78,6 +82,8 @@ __export(redis_smq_exports, {
78
82
  EQueueDeliveryModel: () => EQueueDeliveryModel,
79
83
  EQueueProperty: () => EQueueProperty,
80
84
  EQueueType: () => EQueueType,
85
+ EWorkerThreadMessageCodeConsume: () => EWorkerThreadMessageCodeConsume,
86
+ EWorkerThreadMessageCodeExit: () => EWorkerThreadMessageCodeExit,
81
87
  ExchangeDirect: () => ExchangeDirect,
82
88
  ExchangeError: () => ExchangeError,
83
89
  ExchangeFanOut: () => ExchangeFanOut,
@@ -437,6 +443,22 @@ var EConsumeMessageUnacknowledgedCause = /* @__PURE__ */ ((EConsumeMessageUnackn
437
443
  return EConsumeMessageUnacknowledgedCause3;
438
444
  })(EConsumeMessageUnacknowledgedCause || {});
439
445
 
446
+ // types/consumer/consume-message-worker.ts
447
+ var EWorkerThreadMessageCodeExit = /* @__PURE__ */ ((EWorkerThreadMessageCodeExit2) => {
448
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["WORKER_DATA_REQUIRED"] = 100] = "WORKER_DATA_REQUIRED";
449
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["INVALID_HANDLER_TYPE"] = 101] = "INVALID_HANDLER_TYPE";
450
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["HANDLER_IMPORT_ERROR"] = 102] = "HANDLER_IMPORT_ERROR";
451
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["UNCAUGHT_EXCEPTION"] = 103] = "UNCAUGHT_EXCEPTION";
452
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["TERMINATED"] = 104] = "TERMINATED";
453
+ return EWorkerThreadMessageCodeExit2;
454
+ })(EWorkerThreadMessageCodeExit || {});
455
+ var EWorkerThreadMessageCodeConsume = /* @__PURE__ */ ((EWorkerThreadMessageCodeConsume2) => {
456
+ EWorkerThreadMessageCodeConsume2[EWorkerThreadMessageCodeConsume2["OK"] = 200] = "OK";
457
+ EWorkerThreadMessageCodeConsume2[EWorkerThreadMessageCodeConsume2["MESSAGE_PROCESSING_ERROR"] = 201] = "MESSAGE_PROCESSING_ERROR";
458
+ EWorkerThreadMessageCodeConsume2[EWorkerThreadMessageCodeConsume2["MESSAGE_PROCESSING_CAUGHT_ERROR"] = 202] = "MESSAGE_PROCESSING_CAUGHT_ERROR";
459
+ return EWorkerThreadMessageCodeConsume2;
460
+ })(EWorkerThreadMessageCodeConsume || {});
461
+
440
462
  // types/exchange/common.ts
441
463
  var EExchangeType = /* @__PURE__ */ ((EExchangeType2) => {
442
464
  EExchangeType2[EExchangeType2["DIRECT"] = 0] = "DIRECT";
@@ -674,6 +696,41 @@ var MessageDeleteError = class extends MessageError {
674
696
  }
675
697
  };
676
698
 
699
+ // src/lib/consumer/message-handler/errors/consumer-message-handler.error.ts
700
+ var ConsumerMessageHandlerError = class extends ConsumerError {
701
+ constructor(msg) {
702
+ super(msg);
703
+ }
704
+ };
705
+
706
+ // src/lib/consumer/message-handler/errors/consumer-message-handler-worker.error.ts
707
+ var ConsumerMessageHandlerWorkerError = class extends ConsumerMessageHandlerError {
708
+ constructor(msg) {
709
+ var _a;
710
+ const { code, error } = msg;
711
+ const messageStr = `Error code: ${(_a = EWorkerThreadMessageCodeExit[code]) != null ? _a : EWorkerThreadMessageCodeConsume[code]}.${error ? ` Cause: ${error.name}(${error.message})` : ""}`;
712
+ super(messageStr);
713
+ }
714
+ };
715
+
716
+ // src/lib/consumer/message-handler/errors/consumer-message-handler-filename-extension.error.ts
717
+ var ConsumerMessageHandlerFilenameExtensionError = class extends ConsumerMessageHandlerError {
718
+ constructor() {
719
+ super(
720
+ `Message handler filename must ends with a '.js' or '.cjs' extension depending on your project settings.`
721
+ );
722
+ }
723
+ };
724
+
725
+ // src/lib/consumer/message-handler/errors/consumer-message-handler-file.error.ts
726
+ var ConsumerMessageHandlerFileError = class extends ConsumerMessageHandlerError {
727
+ constructor() {
728
+ super(
729
+ `Make sure the message handler filename is an absolute file path pointing to an existing file in your project. `
730
+ );
731
+ }
732
+ };
733
+
677
734
  // src/lib/consumer/consumer-heartbeat.ts
678
735
  var os = __toESM(require("os"), 1);
679
736
  var import_redis_smq_common10 = require("redis-smq-common");
@@ -981,6 +1038,8 @@ var Base = class extends import_redis_smq_common11.EventEmitter {
981
1038
  };
982
1039
 
983
1040
  // src/lib/consumer/message-handler/message-handler.ts
1041
+ var import_fs = require("fs");
1042
+ var import_path3 = __toESM(require("path"), 1);
984
1043
  var import_uuid4 = require("uuid");
985
1044
 
986
1045
  // src/lib/consumer/message-handler/processing-queue.ts
@@ -1419,6 +1478,13 @@ var MessageEnvelope = class {
1419
1478
  consumerGroupId: this.getConsumerGroupId()
1420
1479
  };
1421
1480
  }
1481
+ transfer() {
1482
+ return __spreadProps(__spreadValues({}, this.toJSON()), {
1483
+ id: this.getId(),
1484
+ messageState: this.getMessageState().toJSON(),
1485
+ status: this.getStatus()
1486
+ });
1487
+ }
1422
1488
  hasRetryThresholdExceeded() {
1423
1489
  const threshold = this.producibleMessage.getRetryThreshold();
1424
1490
  return this.messageState.getAttempts() + 1 >= threshold;
@@ -2679,87 +2745,76 @@ var DequeueMessage = class {
2679
2745
  // src/lib/consumer/message-handler/consume-message.ts
2680
2746
  var import_redis_smq_common24 = require("redis-smq-common");
2681
2747
 
2682
- // src/lib/message/_create-consumable-message.ts
2683
- function _createConsumableMessage(msg) {
2684
- return {
2685
- getPublishedAt() {
2686
- return msg.getPublishedAt();
2687
- },
2688
- getScheduledAt() {
2689
- return msg.getScheduledAt();
2690
- },
2691
- getScheduledMessageId() {
2692
- return msg.getScheduledMessageId();
2693
- },
2694
- getId() {
2695
- return msg.getId();
2696
- },
2697
- getStatus() {
2698
- return msg.getStatus();
2699
- },
2700
- hasPriority() {
2701
- return msg.producibleMessage.hasPriority();
2702
- },
2703
- getQueue() {
2704
- return msg.producibleMessage.getQueue();
2705
- },
2706
- getDestinationQueue() {
2707
- return msg.getDestinationQueue();
2708
- },
2709
- getPriority() {
2710
- return msg.producibleMessage.getPriority();
2711
- },
2712
- getBody() {
2713
- return msg.producibleMessage.getBody();
2714
- },
2715
- getTTL() {
2716
- return msg.producibleMessage.getTTL();
2717
- },
2718
- getRetryThreshold() {
2719
- return msg.producibleMessage.getRetryThreshold();
2720
- },
2721
- getRetryDelay() {
2722
- return msg.producibleMessage.getRetryDelay();
2723
- },
2724
- getConsumeTimeout() {
2725
- return msg.producibleMessage.getConsumeTimeout();
2726
- },
2727
- getCreatedAt() {
2728
- return msg.producibleMessage.getCreatedAt();
2729
- },
2730
- getScheduledRepeat() {
2731
- return msg.producibleMessage.getScheduledRepeat();
2732
- },
2733
- getScheduledRepeatPeriod() {
2734
- return msg.producibleMessage.getScheduledRepeatPeriod();
2735
- },
2736
- getScheduledCRON() {
2737
- return msg.producibleMessage.getScheduledCRON();
2738
- },
2739
- getScheduledDelay() {
2740
- return msg.producibleMessage.getScheduledDelay();
2741
- },
2742
- getFanOut() {
2743
- return msg.producibleMessage.getFanOut();
2744
- },
2745
- getTopic() {
2746
- return msg.producibleMessage.getTopic();
2747
- },
2748
- toJSON() {
2749
- return msg.toJSON();
2750
- },
2751
- getExchange() {
2752
- return msg.getExchange();
2753
- },
2754
- getConsumerGroupId() {
2755
- return msg.getConsumerGroupId();
2748
+ // src/lib/consumer/message-handler/consume-message-worker.ts
2749
+ var import_path2 = __toESM(require("path"), 1);
2750
+ var import_worker_threads = require("worker_threads");
2751
+ var ConsumeMessageWorker = class {
2752
+ constructor(messageHandlerFilename) {
2753
+ this.messageHandlerThread = null;
2754
+ this.messageHandlerFilename = messageHandlerFilename;
2755
+ }
2756
+ getMessageHandlerThread() {
2757
+ if (!this.messageHandlerThread) {
2758
+ this.messageHandlerThread = new import_worker_threads.Worker(
2759
+ import_path2.default.resolve(__dirname, "./consume-message-worker-thread.js"),
2760
+ {
2761
+ workerData: this.messageHandlerFilename
2762
+ }
2763
+ );
2764
+ this.messageHandlerThread.on("messageerror", (err) => {
2765
+ console.error(err);
2766
+ });
2767
+ this.messageHandlerThread.on("error", (err) => {
2768
+ console.error(err);
2769
+ });
2770
+ this.messageHandlerThread.on("exit", () => {
2771
+ this.messageHandlerThread = null;
2772
+ });
2756
2773
  }
2757
- };
2758
- }
2774
+ return this.messageHandlerThread;
2775
+ }
2776
+ consume(message, cb) {
2777
+ const worker = this.getMessageHandlerThread();
2778
+ const cleanUp = () => {
2779
+ worker.removeListener("message", onMessage).removeListener("exit", onExit);
2780
+ };
2781
+ const onMessage = (msg) => {
2782
+ cleanUp();
2783
+ if (msg.code !== 200 /* OK */) {
2784
+ console.error(`ConsumerMessageHandlerWorkerError`, msg);
2785
+ cb(new ConsumerMessageHandlerWorkerError(msg));
2786
+ } else
2787
+ cb();
2788
+ };
2789
+ const onExit = () => {
2790
+ cleanUp();
2791
+ const msg = {
2792
+ code: 104 /* TERMINATED */,
2793
+ error: null
2794
+ };
2795
+ console.error("ConsumerMessageHandlerWorkerError", msg);
2796
+ cb(new ConsumerMessageHandlerWorkerError(msg));
2797
+ };
2798
+ worker.once("message", onMessage);
2799
+ worker.once("exit", onExit);
2800
+ worker.postMessage(message);
2801
+ }
2802
+ quit(cb) {
2803
+ const callback = () => {
2804
+ this.messageHandlerThread = null;
2805
+ cb();
2806
+ };
2807
+ if (this.messageHandlerThread) {
2808
+ this.messageHandlerThread.terminate().then(callback).catch(callback);
2809
+ } else
2810
+ cb();
2811
+ }
2812
+ };
2759
2813
 
2760
2814
  // src/lib/consumer/message-handler/consume-message.ts
2761
2815
  var ConsumeMessage = class {
2762
2816
  constructor(messageHandler, redisClient2, logger3) {
2817
+ this.consumeMessageWorker = null;
2763
2818
  this.redisClient = redisClient2;
2764
2819
  this.messageHandler = messageHandler;
2765
2820
  this.queue = messageHandler.getQueue();
@@ -2843,6 +2898,20 @@ var ConsumeMessage = class {
2843
2898
  }
2844
2899
  );
2845
2900
  }
2901
+ getConsumeMessageWorker(messageHandlerFilename) {
2902
+ if (!this.consumeMessageWorker) {
2903
+ this.consumeMessageWorker = new ConsumeMessageWorker(
2904
+ messageHandlerFilename
2905
+ );
2906
+ }
2907
+ return this.consumeMessageWorker;
2908
+ }
2909
+ invokeMessageHandler(messageHandler, msg, cb) {
2910
+ if (typeof messageHandler === "string") {
2911
+ this.getConsumeMessageWorker(messageHandler).consume(msg, cb);
2912
+ } else
2913
+ messageHandler(msg, cb);
2914
+ }
2846
2915
  consumeMessage(msg) {
2847
2916
  let isTimeout = false;
2848
2917
  let timer = null;
@@ -2884,8 +2953,9 @@ var ConsumeMessage = class {
2884
2953
  }
2885
2954
  }
2886
2955
  };
2887
- this.messageHandler.getHandler()(
2888
- _createConsumableMessage(msg),
2956
+ this.invokeMessageHandler(
2957
+ this.messageHandler.getHandler(),
2958
+ msg.transfer(),
2889
2959
  onConsumed
2890
2960
  );
2891
2961
  } catch (error) {
@@ -2905,6 +2975,12 @@ var ConsumeMessage = class {
2905
2975
  } else
2906
2976
  this.consumeMessage(message);
2907
2977
  }
2978
+ quit(cb) {
2979
+ if (this.consumeMessageWorker) {
2980
+ this.consumeMessageWorker.quit(cb);
2981
+ } else
2982
+ cb();
2983
+ }
2908
2984
  };
2909
2985
 
2910
2986
  // src/lib/consumer/message-handler/message-handler.ts
@@ -2920,7 +2996,7 @@ var MessageHandler = class extends import_redis_smq_common25.EventEmitter {
2920
2996
  this.dequeueRedisClient = dequeueRedisClient;
2921
2997
  this.sharedRedisClient = sharedRedisClient;
2922
2998
  this.handler = messageHandler;
2923
- this.powerSwitch = new import_redis_smq_common25.PowerSwitch();
2999
+ this.powerSwitch = new import_redis_smq_common25.PowerSwitch(false);
2924
3000
  this.logger = logger3;
2925
3001
  this.dequeueMessage = new DequeueMessage(this, dequeueRedisClient);
2926
3002
  this.consumeMessage = new ConsumeMessage(this, dequeueRedisClient, logger3);
@@ -3010,6 +3086,17 @@ var MessageHandler = class extends import_redis_smq_common25.EventEmitter {
3010
3086
  shutdownDequeueClient(cb) {
3011
3087
  this.dequeueRedisClient.halt(cb);
3012
3088
  }
3089
+ forceShutDown(cb) {
3090
+ this.powerSwitch.rollback();
3091
+ import_redis_smq_common25.async.waterfall(
3092
+ [
3093
+ (cb2) => this.dequeueMessage.quit(cb2),
3094
+ (cb2) => this.consumeMessage.quit(cb2),
3095
+ (cb2) => this.shutdownDequeueClient(cb2)
3096
+ ],
3097
+ cb
3098
+ );
3099
+ }
3013
3100
  handleError(err) {
3014
3101
  if (this.powerSwitch.isRunning() || this.powerSwitch.isGoingUp()) {
3015
3102
  this.emit("error", err);
@@ -3020,35 +3107,63 @@ var MessageHandler = class extends import_redis_smq_common25.EventEmitter {
3020
3107
  }
3021
3108
  run(cb) {
3022
3109
  this.powerSwitch.goingUp();
3023
- this.dequeueMessage.run((err) => {
3024
- if (err)
3025
- cb(err);
3026
- else {
3027
- this.powerSwitch.commit();
3028
- this.emit("up");
3029
- cb();
3110
+ import_redis_smq_common25.async.waterfall(
3111
+ [
3112
+ (cb2) => {
3113
+ if (typeof this.handler === "string") {
3114
+ if (![".js", ".cjs"].includes(import_path3.default.extname(this.handler))) {
3115
+ cb2(new ConsumerMessageHandlerFilenameExtensionError());
3116
+ } else
3117
+ (0, import_fs.stat)(this.handler, (err) => {
3118
+ if (err)
3119
+ cb2(new ConsumerMessageHandlerFileError());
3120
+ else
3121
+ cb2();
3122
+ });
3123
+ } else
3124
+ cb2();
3125
+ },
3126
+ (cb2) => this.dequeueMessage.run((err) => {
3127
+ if (err)
3128
+ cb2(err);
3129
+ else {
3130
+ this.powerSwitch.commit();
3131
+ this.emit("up");
3132
+ cb2();
3133
+ }
3134
+ })
3135
+ ],
3136
+ (err) => {
3137
+ if (err)
3138
+ this.forceShutDown(() => cb(err));
3139
+ else
3140
+ cb();
3030
3141
  }
3031
- });
3142
+ );
3032
3143
  }
3033
3144
  shutdown(messageUnacknowledgedCause, cb) {
3034
3145
  const goDown = () => {
3035
- this.powerSwitch.goingDown();
3036
- import_redis_smq_common25.async.waterfall(
3037
- [
3038
- (cb2) => this.dequeueMessage.quit(cb2),
3039
- (cb2) => this.cleanUp(messageUnacknowledgedCause, cb2),
3040
- (cb2) => this.shutdownDequeueClient(cb2)
3041
- ],
3042
- (err) => {
3043
- if (err)
3044
- cb(err);
3045
- else {
3046
- this.powerSwitch.commit();
3047
- this.emit("down");
3048
- cb();
3146
+ const r = this.powerSwitch.goingDown();
3147
+ if (r) {
3148
+ import_redis_smq_common25.async.waterfall(
3149
+ [
3150
+ (cb2) => this.dequeueMessage.quit(cb2),
3151
+ (cb2) => this.consumeMessage.quit(cb2),
3152
+ (cb2) => this.cleanUp(messageUnacknowledgedCause, cb2),
3153
+ (cb2) => this.shutdownDequeueClient(cb2)
3154
+ ],
3155
+ (err) => {
3156
+ if (err)
3157
+ cb(err);
3158
+ else {
3159
+ this.powerSwitch.commit();
3160
+ this.emit("down");
3161
+ cb();
3162
+ }
3049
3163
  }
3050
- }
3051
- );
3164
+ );
3165
+ } else
3166
+ cb();
3052
3167
  };
3053
3168
  if (this.powerSwitch.isGoingUp())
3054
3169
  this.once("up", goDown);
@@ -3147,7 +3262,12 @@ var MessageHandlerRunner = class {
3147
3262
  client,
3148
3263
  handlerParams
3149
3264
  );
3150
- handler.run(cb);
3265
+ handler.run((err2) => {
3266
+ if (err2)
3267
+ this.removeMessageHandler(handlerParams.queue, () => cb(err2));
3268
+ else
3269
+ cb();
3270
+ });
3151
3271
  }
3152
3272
  });
3153
3273
  }
@@ -4488,7 +4608,7 @@ var Message = class {
4488
4608
  else {
4489
4609
  cb(
4490
4610
  null,
4491
- reply.map((i) => _createConsumableMessage(i))
4611
+ reply.map((i) => i.transfer())
4492
4612
  );
4493
4613
  }
4494
4614
  });
@@ -4507,7 +4627,7 @@ var Message = class {
4507
4627
  else if (!reply)
4508
4628
  cb(new import_redis_smq_common36.CallbackEmptyReplyError());
4509
4629
  else
4510
- cb(null, _createConsumableMessage(reply));
4630
+ cb(null, reply.transfer());
4511
4631
  });
4512
4632
  });
4513
4633
  }
@@ -5727,6 +5847,10 @@ function disconnect(cb) {
5727
5847
  ConsumerGroups,
5728
5848
  ConsumerInvalidGroupIdError,
5729
5849
  ConsumerMessageHandlerAlreadyExistsError,
5850
+ ConsumerMessageHandlerError,
5851
+ ConsumerMessageHandlerFileError,
5852
+ ConsumerMessageHandlerFilenameExtensionError,
5853
+ ConsumerMessageHandlerWorkerError,
5730
5854
  EConsumeMessageDeadLetterCause,
5731
5855
  EConsumeMessageUnacknowledgedCause,
5732
5856
  EExchangeType,
@@ -5736,6 +5860,8 @@ function disconnect(cb) {
5736
5860
  EQueueDeliveryModel,
5737
5861
  EQueueProperty,
5738
5862
  EQueueType,
5863
+ EWorkerThreadMessageCodeConsume,
5864
+ EWorkerThreadMessageCodeExit,
5739
5865
  ExchangeDirect,
5740
5866
  ExchangeError,
5741
5867
  ExchangeFanOut,