bullmq 6.0.8 → 6.0.10

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <br/>
5
5
  <br/>
6
6
  <p>
7
- The fastest, most reliable, Redis-based distributed queue for Node.js, Python, Elixir, Rust, PHP, and more. <br/>
7
+ The fastest, most reliable, Redis-based distributed queue for Node.js, Python, Elixir, .NET, Rust, PHP, and more. <br/>
8
8
  Carefully written for rock solid stability and atomicity.
9
9
  </p>
10
10
  Read the <a href="https://docs.bullmq.io">documentation</a>
@@ -46,6 +46,7 @@ BullMQ is available natively in multiple languages:
46
46
  - **Python** — [`python/`](./python) directory (`pip install bullmq`)
47
47
  - **Rust** — [`rust/`](./rust) directory (`cargo add bullmq-official --rename bullmq`)
48
48
  - **Elixir** — [`elixir/`](./elixir) directory (`{:bullmq, "~> x.x"}`)
49
+ - **.Net** — [`dotnet/`](./dotnet) directory (`dotnet add package BullMQ`)
49
50
  - **PHP** — [`php/`](./php) directory
50
51
 
51
52
  For other platforms, check out the [BullMQ Proxy](https://github.com/taskforcesh/bullmq-proxy).
@@ -8,26 +8,6 @@ exports.isIRedisClient = isIRedisClient;
8
8
  * event-listener identity for the BullMQ-facing client.
9
9
  */
10
10
  const proxyCache = new WeakMap();
11
- /**
12
- * Wraps an ioredis `Redis` / `Cluster` instance with a `Proxy` so it conforms
13
- * to {@link IRedisClient}.
14
- *
15
- * For backwards compatibility BullMQ continues to accept a raw `IORedis`
16
- * instance through tehe `connection` option, even though internally it relies
17
- * on the `IRedisClient` adapter interface. The returned proxy:
18
- *
19
- * - exposes `runCommand` (Lua script dispatch by name)
20
- * - exposes structured-options variants of `hset`, `set`, `zrange`,
21
- * `zrevrange`, `xadd`, `xread`, `xtrim`, `scan` (backward-compatible:
22
- * they still accept native ioredis varargs if called that way)
23
- * - returns augmented {@link IRedisTransaction}s from `pipeline()` / `multi()`
24
- * - wraps the result of `duplicate()` in a new proxy
25
- *
26
- * The underlying ioredis instance is **not** mutated. Properties and methods
27
- * not in the override table are forwarded to the raw client via the proxy
28
- * traps, with `this === target` so EventEmitter / Commander internals work
29
- * normally.
30
- */
31
11
  function createIORedisClient(client) {
32
12
  // If the caller already passed a proxy produced by this function, return
33
13
  // it as-is. Wrapping a proxy in a second proxy would defeat the WeakMap
@@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RedisConnection = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const events_1 = require("events");
6
- const ioredis_1 = require("ioredis");
7
6
  const utils_1 = require("../utils");
8
7
  const version_1 = require("../version");
9
8
  const scripts = require("../scripts");
10
9
  const ioredis_client_1 = require("./ioredis-client");
10
+ const node_redis_client_1 = require("./node-redis-client");
11
+ const bun_redis_client_1 = require("./bun-redis-client");
11
12
  const connection_closed_error_1 = require("./errors/connection-closed-error");
12
13
  const overrideMessage = [
13
14
  'BullMQ: WARNING! Your redis options maxRetriesPerRequest must be null',
@@ -27,6 +28,75 @@ const clusterClosingRefCount = Symbol('bullmqClusterClosingRefCount');
27
28
  // the worker. 30s is comfortably above the default ioredis slotsRefreshTimeout
28
29
  // while bounded enough that wedged workers recover within one or two ticks.
29
30
  const DEFAULT_CLUSTER_RECONNECT_TIMEOUT_MS = 30000;
31
+ /**
32
+ * Lazily loads the optional `ioredis` driver. Users on another Redis driver
33
+ * (node-redis, Bun built-in, …) or on the PostgreSQL backend never hit this
34
+ * path, so they never need `ioredis` installed.
35
+ *
36
+ * Only reached when no {@link RedisConnection.clientFactory} is set and the
37
+ * caller did not pass an already-constructed client instance. In native ESM
38
+ * environments where `require` is unavailable, callers should provide a client
39
+ * instance or a `clientFactory` instead.
40
+ */
41
+ function loadIORedis() {
42
+ var _a;
43
+ try {
44
+ if (typeof require === 'function') {
45
+ const mod = require('ioredis');
46
+ // ioredis exports the constructor both as the module itself (CJS) and
47
+ // under `default` (ESM interop); normalise to the constructor.
48
+ return (_a = mod.default) !== null && _a !== void 0 ? _a : mod;
49
+ }
50
+ }
51
+ catch (_b) {
52
+ // Fall through to the friendly error below.
53
+ }
54
+ throw new Error("BullMQ could not load the optional 'ioredis' package. " +
55
+ 'Install it with `npm install ioredis`, or provide a different Redis ' +
56
+ 'client instance (e.g. node-redis) via the connection option. In a ' +
57
+ 'native ESM environment, pass an already-constructed client instance ' +
58
+ 'instead of connection options.');
59
+ }
60
+ /**
61
+ * Wraps a raw client instance passed through the `connection` option in the
62
+ * matching {@link IRedisClient} adapter, auto-detecting the underlying driver.
63
+ *
64
+ * This lets consumers pass a native node-redis or Bun client directly (without
65
+ * manually calling `createNodeRedisClient` / `createBunRedisClient` or setting a
66
+ * global {@link RedisConnection.clientFactory}), so those users never need
67
+ * `ioredis` installed. ioredis instances keep their existing code path, so the
68
+ * behaviour is fully backwards compatible.
69
+ *
70
+ * Detection is purely structural (no driver package is imported), keying off
71
+ * markers that are unique to each client:
72
+ * - ioredis exposes `defineCommand` (used to register Lua scripts);
73
+ * node-redis and Bun do not.
74
+ * - node-redis (`@redis/client`) exposes `sendCommand` plus `isOpen`/`isReady`.
75
+ * - Bun's built-in `RedisClient` exposes `send` plus a `connected` flag.
76
+ */
77
+ function wrapRedisInstance(instance) {
78
+ // Already an adapted IRedisClient (ioredis proxy, node-redis, Bun, or a
79
+ // custom implementation) — use as-is.
80
+ if ((0, ioredis_client_1.isIRedisClient)(instance)) {
81
+ return instance;
82
+ }
83
+ const hasDefineCommand = typeof instance.defineCommand === 'function';
84
+ // node-redis (@redis/client): `sendCommand` + `isOpen`/`isReady`, and no
85
+ // ioredis-style `defineCommand`.
86
+ if (!hasDefineCommand &&
87
+ typeof instance.sendCommand === 'function' &&
88
+ ('isOpen' in instance || 'isReady' in instance)) {
89
+ return (0, node_redis_client_1.createNodeRedisClient)(instance);
90
+ }
91
+ // Bun's built-in RedisClient: `send` + `connected`, and no `defineCommand`.
92
+ if (!hasDefineCommand &&
93
+ typeof instance.send === 'function' &&
94
+ 'connected' in instance) {
95
+ return (0, bun_redis_client_1.createBunRedisClient)(instance);
96
+ }
97
+ // Default: treat as an ioredis instance (backwards compatible).
98
+ return (0, ioredis_client_1.createIORedisClient)(instance);
99
+ }
30
100
  class RedisConnection extends events_1.EventEmitter {
31
101
  constructor(opts, extraOptions) {
32
102
  super();
@@ -51,10 +121,10 @@ class RedisConnection extends events_1.EventEmitter {
51
121
  }
52
122
  }
53
123
  else {
54
- // Wrap raw ioredis instances in the IRedisClient adapter if not already wrapped
55
- this._client = (0, ioredis_client_1.isIRedisClient)(opts)
56
- ? opts
57
- : (0, ioredis_client_1.createIORedisClient)(opts);
124
+ // Wrap raw client instances in the matching IRedisClient adapter,
125
+ // auto-detecting the driver (ioredis / node-redis / Bun) so callers can
126
+ // pass a native client directly without setting a clientFactory.
127
+ this._client = wrapRedisInstance(opts);
58
128
  // Test if the redis instance is using keyPrefix
59
129
  // and if so, throw an error.
60
130
  if (this._client.options.keyPrefix) {
@@ -187,7 +257,10 @@ class RedisConnection extends events_1.EventEmitter {
187
257
  }
188
258
  else {
189
259
  const _a = this.opts, { url } = _a, rest = tslib_1.__rest(_a, ["url"]);
190
- const ioredisClient = url ? new ioredis_1.default(url, rest) : new ioredis_1.default(rest);
260
+ const IORedisCtor = loadIORedis();
261
+ const ioredisClient = url
262
+ ? new IORedisCtor(url, rest)
263
+ : new IORedisCtor(rest);
191
264
  this._client = (0, ioredis_client_1.createIORedisClient)(ioredisClient);
192
265
  }
193
266
  }