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

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,34 @@
1
1
 
2
2
 
3
+ ## [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)
4
+
5
+
6
+ ### Features
7
+
8
+ * allow running/sandboxing message handlers using worker threads ([53095bd](https://github.com/weyoss/redis-smq/commit/53095bd2689ccb2f701365bafb4ef8e550da82b3))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * export message handler errors ([26d2689](https://github.com/weyoss/redis-smq/commit/26d26890da139d88c46ce220e3dda3d9c8e03aee))
14
+
15
+
16
+ ### Documentation
17
+
18
+ * **ConsumeMessageWorker:** update docs and clean up ([140322e](https://github.com/weyoss/redis-smq/commit/140322e3520ee3db905ea977a159064f339aa7d2))
19
+ * fix broken links ([aad9010](https://github.com/weyoss/redis-smq/commit/aad9010e70ed332b154f4fbdcb8ac657a14fe6b9))
20
+ * update messages and queues documentation ([7c3d06e](https://github.com/weyoss/redis-smq/commit/7c3d06ed3765ffc14dfece4f725241aa4535e1e7))
21
+
22
+
23
+ ### Codebase Refactoring
24
+
25
+ * **ConsumeMessageWorker:** improve typings ([66c6ca9](https://github.com/weyoss/redis-smq/commit/66c6ca948677f76d496fe0b988bd195e1a7108a2))
26
+
27
+
28
+ ### Tests
29
+
30
+ * allow running/sandboxing message handlers using worker threads ([79e6886](https://github.com/weyoss/redis-smq/commit/79e688674ed11ec34ce2f74d5f15c8eefa129767))
31
+
3
32
  ## [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
33
 
5
34
 
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,8 @@ __export(redis_smq_exports, {
69
69
  ConsumerGroups: () => ConsumerGroups,
70
70
  ConsumerInvalidGroupIdError: () => ConsumerInvalidGroupIdError,
71
71
  ConsumerMessageHandlerAlreadyExistsError: () => ConsumerMessageHandlerAlreadyExistsError,
72
+ ConsumerMessageHandlerError: () => ConsumerMessageHandlerError,
73
+ ConsumerMessageHandlerWorkerError: () => ConsumerMessageHandlerWorkerError,
72
74
  EConsumeMessageDeadLetterCause: () => EConsumeMessageDeadLetterCause,
73
75
  EConsumeMessageUnacknowledgedCause: () => EConsumeMessageUnacknowledgedCause,
74
76
  EExchangeType: () => EExchangeType,
@@ -78,6 +80,8 @@ __export(redis_smq_exports, {
78
80
  EQueueDeliveryModel: () => EQueueDeliveryModel,
79
81
  EQueueProperty: () => EQueueProperty,
80
82
  EQueueType: () => EQueueType,
83
+ EWorkerThreadMessageCodeConsume: () => EWorkerThreadMessageCodeConsume,
84
+ EWorkerThreadMessageCodeExit: () => EWorkerThreadMessageCodeExit,
81
85
  ExchangeDirect: () => ExchangeDirect,
82
86
  ExchangeError: () => ExchangeError,
83
87
  ExchangeFanOut: () => ExchangeFanOut,
@@ -437,6 +441,22 @@ var EConsumeMessageUnacknowledgedCause = /* @__PURE__ */ ((EConsumeMessageUnackn
437
441
  return EConsumeMessageUnacknowledgedCause3;
438
442
  })(EConsumeMessageUnacknowledgedCause || {});
439
443
 
444
+ // types/consumer/consume-message-worker.ts
445
+ var EWorkerThreadMessageCodeExit = /* @__PURE__ */ ((EWorkerThreadMessageCodeExit2) => {
446
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["WORKER_DATA_REQUIRED"] = 100] = "WORKER_DATA_REQUIRED";
447
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["INVALID_HANDLER_TYPE"] = 101] = "INVALID_HANDLER_TYPE";
448
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["HANDLER_IMPORT_ERROR"] = 102] = "HANDLER_IMPORT_ERROR";
449
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["UNCAUGHT_EXCEPTION"] = 103] = "UNCAUGHT_EXCEPTION";
450
+ EWorkerThreadMessageCodeExit2[EWorkerThreadMessageCodeExit2["TERMINATED"] = 104] = "TERMINATED";
451
+ return EWorkerThreadMessageCodeExit2;
452
+ })(EWorkerThreadMessageCodeExit || {});
453
+ var EWorkerThreadMessageCodeConsume = /* @__PURE__ */ ((EWorkerThreadMessageCodeConsume2) => {
454
+ EWorkerThreadMessageCodeConsume2[EWorkerThreadMessageCodeConsume2["OK"] = 200] = "OK";
455
+ EWorkerThreadMessageCodeConsume2[EWorkerThreadMessageCodeConsume2["MESSAGE_PROCESSING_ERROR"] = 201] = "MESSAGE_PROCESSING_ERROR";
456
+ EWorkerThreadMessageCodeConsume2[EWorkerThreadMessageCodeConsume2["MESSAGE_PROCESSING_CAUGHT_ERROR"] = 202] = "MESSAGE_PROCESSING_CAUGHT_ERROR";
457
+ return EWorkerThreadMessageCodeConsume2;
458
+ })(EWorkerThreadMessageCodeConsume || {});
459
+
440
460
  // types/exchange/common.ts
441
461
  var EExchangeType = /* @__PURE__ */ ((EExchangeType2) => {
442
462
  EExchangeType2[EExchangeType2["DIRECT"] = 0] = "DIRECT";
@@ -674,6 +694,23 @@ var MessageDeleteError = class extends MessageError {
674
694
  }
675
695
  };
676
696
 
697
+ // src/lib/consumer/message-handler/errors/consumer-message-handler.error.ts
698
+ var ConsumerMessageHandlerError = class extends ConsumerError {
699
+ constructor(msg) {
700
+ super(msg);
701
+ }
702
+ };
703
+
704
+ // src/lib/consumer/message-handler/errors/consumer-message-handler-worker.error.ts
705
+ var ConsumerMessageHandlerWorkerError = class extends ConsumerMessageHandlerError {
706
+ constructor(msg) {
707
+ const { code, error } = msg;
708
+ super(
709
+ `Error code: ${code}.${error ? `Message: ${error.name}: ${error.message}` : ""}`
710
+ );
711
+ }
712
+ };
713
+
677
714
  // src/lib/consumer/consumer-heartbeat.ts
678
715
  var os = __toESM(require("os"), 1);
679
716
  var import_redis_smq_common10 = require("redis-smq-common");
@@ -981,6 +1018,8 @@ var Base = class extends import_redis_smq_common11.EventEmitter {
981
1018
  };
982
1019
 
983
1020
  // src/lib/consumer/message-handler/message-handler.ts
1021
+ var import_fs = require("fs");
1022
+ var import_path3 = __toESM(require("path"), 1);
984
1023
  var import_uuid4 = require("uuid");
985
1024
 
986
1025
  // src/lib/consumer/message-handler/processing-queue.ts
@@ -1419,6 +1458,13 @@ var MessageEnvelope = class {
1419
1458
  consumerGroupId: this.getConsumerGroupId()
1420
1459
  };
1421
1460
  }
1461
+ transfer() {
1462
+ return __spreadProps(__spreadValues({}, this.toJSON()), {
1463
+ id: this.getId(),
1464
+ messageState: this.getMessageState().toJSON(),
1465
+ status: this.getStatus()
1466
+ });
1467
+ }
1422
1468
  hasRetryThresholdExceeded() {
1423
1469
  const threshold = this.producibleMessage.getRetryThreshold();
1424
1470
  return this.messageState.getAttempts() + 1 >= threshold;
@@ -2679,87 +2725,76 @@ var DequeueMessage = class {
2679
2725
  // src/lib/consumer/message-handler/consume-message.ts
2680
2726
  var import_redis_smq_common24 = require("redis-smq-common");
2681
2727
 
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();
2728
+ // src/lib/consumer/message-handler/consume-message-worker.ts
2729
+ var import_path2 = __toESM(require("path"), 1);
2730
+ var import_worker_threads = require("worker_threads");
2731
+ var ConsumeMessageWorker = class {
2732
+ constructor(messageHandlerFilename) {
2733
+ this.messageHandlerThread = null;
2734
+ this.messageHandlerFilename = messageHandlerFilename;
2735
+ }
2736
+ getMessageHandlerThread() {
2737
+ if (!this.messageHandlerThread) {
2738
+ this.messageHandlerThread = new import_worker_threads.Worker(
2739
+ import_path2.default.resolve(__dirname, "./consume-message-worker-thread.js"),
2740
+ {
2741
+ workerData: this.messageHandlerFilename
2742
+ }
2743
+ );
2744
+ this.messageHandlerThread.on("messageerror", (err) => {
2745
+ console.error(err);
2746
+ });
2747
+ this.messageHandlerThread.on("error", (err) => {
2748
+ console.error(err);
2749
+ });
2750
+ this.messageHandlerThread.on("exit", () => {
2751
+ this.messageHandlerThread = null;
2752
+ });
2756
2753
  }
2757
- };
2758
- }
2754
+ return this.messageHandlerThread;
2755
+ }
2756
+ consume(message, cb) {
2757
+ const worker = this.getMessageHandlerThread();
2758
+ const cleanUp = () => {
2759
+ worker.removeListener("message", onMessage).removeListener("exit", onExit);
2760
+ };
2761
+ const onMessage = (msg) => {
2762
+ cleanUp();
2763
+ if (msg.code !== 200 /* OK */) {
2764
+ console.error(`ConsumerMessageHandlerWorkerError`, msg);
2765
+ cb(new ConsumerMessageHandlerWorkerError(msg));
2766
+ } else
2767
+ cb();
2768
+ };
2769
+ const onExit = () => {
2770
+ cleanUp();
2771
+ const msg = {
2772
+ code: 104 /* TERMINATED */,
2773
+ error: null
2774
+ };
2775
+ console.error("ConsumerMessageHandlerWorkerError", msg);
2776
+ cb(new ConsumerMessageHandlerWorkerError(msg));
2777
+ };
2778
+ worker.once("message", onMessage);
2779
+ worker.once("exit", onExit);
2780
+ worker.postMessage(message);
2781
+ }
2782
+ quit(cb) {
2783
+ const callback = () => {
2784
+ this.messageHandlerThread = null;
2785
+ cb();
2786
+ };
2787
+ if (this.messageHandlerThread) {
2788
+ this.messageHandlerThread.terminate().then(callback).catch(callback);
2789
+ } else
2790
+ cb();
2791
+ }
2792
+ };
2759
2793
 
2760
2794
  // src/lib/consumer/message-handler/consume-message.ts
2761
2795
  var ConsumeMessage = class {
2762
2796
  constructor(messageHandler, redisClient2, logger3) {
2797
+ this.consumeMessageWorker = null;
2763
2798
  this.redisClient = redisClient2;
2764
2799
  this.messageHandler = messageHandler;
2765
2800
  this.queue = messageHandler.getQueue();
@@ -2843,6 +2878,20 @@ var ConsumeMessage = class {
2843
2878
  }
2844
2879
  );
2845
2880
  }
2881
+ getConsumeMessageWorker(messageHandlerFilename) {
2882
+ if (!this.consumeMessageWorker) {
2883
+ this.consumeMessageWorker = new ConsumeMessageWorker(
2884
+ messageHandlerFilename
2885
+ );
2886
+ }
2887
+ return this.consumeMessageWorker;
2888
+ }
2889
+ invokeMessageHandler(messageHandler, msg, cb) {
2890
+ if (typeof messageHandler === "string") {
2891
+ this.getConsumeMessageWorker(messageHandler).consume(msg, cb);
2892
+ } else
2893
+ messageHandler(msg, cb);
2894
+ }
2846
2895
  consumeMessage(msg) {
2847
2896
  let isTimeout = false;
2848
2897
  let timer = null;
@@ -2884,8 +2933,9 @@ var ConsumeMessage = class {
2884
2933
  }
2885
2934
  }
2886
2935
  };
2887
- this.messageHandler.getHandler()(
2888
- _createConsumableMessage(msg),
2936
+ this.invokeMessageHandler(
2937
+ this.messageHandler.getHandler(),
2938
+ msg.transfer(),
2889
2939
  onConsumed
2890
2940
  );
2891
2941
  } catch (error) {
@@ -2905,6 +2955,12 @@ var ConsumeMessage = class {
2905
2955
  } else
2906
2956
  this.consumeMessage(message);
2907
2957
  }
2958
+ quit(cb) {
2959
+ if (this.consumeMessageWorker) {
2960
+ this.consumeMessageWorker.quit(cb);
2961
+ } else
2962
+ cb();
2963
+ }
2908
2964
  };
2909
2965
 
2910
2966
  // src/lib/consumer/message-handler/message-handler.ts
@@ -2920,7 +2976,7 @@ var MessageHandler = class extends import_redis_smq_common25.EventEmitter {
2920
2976
  this.dequeueRedisClient = dequeueRedisClient;
2921
2977
  this.sharedRedisClient = sharedRedisClient;
2922
2978
  this.handler = messageHandler;
2923
- this.powerSwitch = new import_redis_smq_common25.PowerSwitch();
2979
+ this.powerSwitch = new import_redis_smq_common25.PowerSwitch(false);
2924
2980
  this.logger = logger3;
2925
2981
  this.dequeueMessage = new DequeueMessage(this, dequeueRedisClient);
2926
2982
  this.consumeMessage = new ConsumeMessage(this, dequeueRedisClient, logger3);
@@ -3010,6 +3066,17 @@ var MessageHandler = class extends import_redis_smq_common25.EventEmitter {
3010
3066
  shutdownDequeueClient(cb) {
3011
3067
  this.dequeueRedisClient.halt(cb);
3012
3068
  }
3069
+ forceShutDown(cb) {
3070
+ this.powerSwitch.rollback();
3071
+ import_redis_smq_common25.async.waterfall(
3072
+ [
3073
+ (cb2) => this.dequeueMessage.quit(cb2),
3074
+ (cb2) => this.consumeMessage.quit(cb2),
3075
+ (cb2) => this.shutdownDequeueClient(cb2)
3076
+ ],
3077
+ cb
3078
+ );
3079
+ }
3013
3080
  handleError(err) {
3014
3081
  if (this.powerSwitch.isRunning() || this.powerSwitch.isGoingUp()) {
3015
3082
  this.emit("error", err);
@@ -3020,35 +3087,63 @@ var MessageHandler = class extends import_redis_smq_common25.EventEmitter {
3020
3087
  }
3021
3088
  run(cb) {
3022
3089
  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();
3090
+ import_redis_smq_common25.async.waterfall(
3091
+ [
3092
+ (cb2) => {
3093
+ if (typeof this.handler === "string") {
3094
+ if (![".js", ".cjs"].includes(import_path3.default.extname(this.handler))) {
3095
+ cb2(new ConsumerMessageHandlerError("Invalid file extension"));
3096
+ } else
3097
+ (0, import_fs.stat)(this.handler, (err) => {
3098
+ if (err)
3099
+ cb2(new ConsumerMessageHandlerError(err.message));
3100
+ else
3101
+ cb2();
3102
+ });
3103
+ } else
3104
+ cb2();
3105
+ },
3106
+ (cb2) => this.dequeueMessage.run((err) => {
3107
+ if (err)
3108
+ cb2(err);
3109
+ else {
3110
+ this.powerSwitch.commit();
3111
+ this.emit("up");
3112
+ cb2();
3113
+ }
3114
+ })
3115
+ ],
3116
+ (err) => {
3117
+ if (err)
3118
+ this.forceShutDown(() => cb(err));
3119
+ else
3120
+ cb();
3030
3121
  }
3031
- });
3122
+ );
3032
3123
  }
3033
3124
  shutdown(messageUnacknowledgedCause, cb) {
3034
3125
  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();
3126
+ const r = this.powerSwitch.goingDown();
3127
+ if (r) {
3128
+ import_redis_smq_common25.async.waterfall(
3129
+ [
3130
+ (cb2) => this.dequeueMessage.quit(cb2),
3131
+ (cb2) => this.consumeMessage.quit(cb2),
3132
+ (cb2) => this.cleanUp(messageUnacknowledgedCause, cb2),
3133
+ (cb2) => this.shutdownDequeueClient(cb2)
3134
+ ],
3135
+ (err) => {
3136
+ if (err)
3137
+ cb(err);
3138
+ else {
3139
+ this.powerSwitch.commit();
3140
+ this.emit("down");
3141
+ cb();
3142
+ }
3049
3143
  }
3050
- }
3051
- );
3144
+ );
3145
+ } else
3146
+ cb();
3052
3147
  };
3053
3148
  if (this.powerSwitch.isGoingUp())
3054
3149
  this.once("up", goDown);
@@ -3147,7 +3242,12 @@ var MessageHandlerRunner = class {
3147
3242
  client,
3148
3243
  handlerParams
3149
3244
  );
3150
- handler.run(cb);
3245
+ handler.run((err2) => {
3246
+ if (err2)
3247
+ this.removeMessageHandler(handlerParams.queue, () => cb(err2));
3248
+ else
3249
+ cb();
3250
+ });
3151
3251
  }
3152
3252
  });
3153
3253
  }
@@ -4488,7 +4588,7 @@ var Message = class {
4488
4588
  else {
4489
4589
  cb(
4490
4590
  null,
4491
- reply.map((i) => _createConsumableMessage(i))
4591
+ reply.map((i) => i.transfer())
4492
4592
  );
4493
4593
  }
4494
4594
  });
@@ -4507,7 +4607,7 @@ var Message = class {
4507
4607
  else if (!reply)
4508
4608
  cb(new import_redis_smq_common36.CallbackEmptyReplyError());
4509
4609
  else
4510
- cb(null, _createConsumableMessage(reply));
4610
+ cb(null, reply.transfer());
4511
4611
  });
4512
4612
  });
4513
4613
  }
@@ -5727,6 +5827,8 @@ function disconnect(cb) {
5727
5827
  ConsumerGroups,
5728
5828
  ConsumerInvalidGroupIdError,
5729
5829
  ConsumerMessageHandlerAlreadyExistsError,
5830
+ ConsumerMessageHandlerError,
5831
+ ConsumerMessageHandlerWorkerError,
5730
5832
  EConsumeMessageDeadLetterCause,
5731
5833
  EConsumeMessageUnacknowledgedCause,
5732
5834
  EExchangeType,
@@ -5736,6 +5838,8 @@ function disconnect(cb) {
5736
5838
  EQueueDeliveryModel,
5737
5839
  EQueueProperty,
5738
5840
  EQueueType,
5841
+ EWorkerThreadMessageCodeConsume,
5842
+ EWorkerThreadMessageCodeExit,
5739
5843
  ExchangeDirect,
5740
5844
  ExchangeError,
5741
5845
  ExchangeFanOut,