@mondart/nestjs-common-module-bottleneck 3.2.11 → 3.2.13
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 +40 -0
- package/dist/interceptors/bottleneck.interceptor.d.ts.map +1 -1
- package/dist/interceptors/bottleneck.interceptor.js +6 -1
- package/dist/interceptors/bottleneck.interceptor.js.map +1 -1
- package/dist/interfaces/bottleneck-options.interface.d.ts +2 -0
- package/dist/interfaces/bottleneck-options.interface.d.ts.map +1 -1
- package/dist/services/bottleneck.service.d.ts +7 -1
- package/dist/services/bottleneck.service.d.ts.map +1 -1
- package/dist/services/bottleneck.service.js +82 -10
- package/dist/services/bottleneck.service.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -52,6 +52,46 @@ To share limits across instances instead of throttling each process
|
|
|
52
52
|
independently, set `useRedis: true` and provide `redis: { host, port, ... }`
|
|
53
53
|
— it's passed straight through to Bottleneck's `ioredis` datastore.
|
|
54
54
|
|
|
55
|
+
### When Redis is unreachable
|
|
56
|
+
|
|
57
|
+
Throttling is best-effort; the work is not. If a limiter fails because Redis
|
|
58
|
+
cannot be reached (`ECONNREFUSED`, a closed connection, retries exhausted) or
|
|
59
|
+
because it answered but cannot serve the write (`READONLY` during a failover,
|
|
60
|
+
`LOADING`, `OOM`, `CLUSTERDOWN`), the task runs **unthrottled** instead of
|
|
61
|
+
failing the caller, and Redis is skipped entirely for the next 5 seconds so an
|
|
62
|
+
outage costs one timeout rather than one per request. Each window opens with
|
|
63
|
+
an `ERROR` log naming the cause. Limits are not enforced while it is open — if
|
|
64
|
+
a route must fail closed instead, throttle it outside this service.
|
|
65
|
+
|
|
66
|
+
Commands default to `maxRetriesPerRequest: 2` (ioredis' own default of 20
|
|
67
|
+
leaves a request hanging ~30s before it fails); override it with
|
|
68
|
+
`redis.maxRetriesPerRequest`.
|
|
69
|
+
|
|
70
|
+
A limiter whose Redis state went stale — `SETTINGS_KEY_NOT_FOUND` when its
|
|
71
|
+
settings key expired, `UNKNOWN_CLIENT` when another replica swept its client —
|
|
72
|
+
is dropped and rebuilt once, then the task is retried. The retry cannot
|
|
73
|
+
duplicate the callback: the script that fails runs before the job is
|
|
74
|
+
registered.
|
|
75
|
+
|
|
76
|
+
### Job expiration
|
|
77
|
+
|
|
78
|
+
Every job gets `expiration: 60000` by default. This is not optional
|
|
79
|
+
bookkeeping: Bottleneck reclaims a slot for a dead client only through
|
|
80
|
+
`job_expirations` (`register.lua`), and its unresponsive-client sweep skips
|
|
81
|
+
any client whose running weight is still above zero (`process_tick.lua`). So
|
|
82
|
+
without an expiration, a process killed mid-job (SIGKILL, OOM, crash) never
|
|
83
|
+
releases its slot, and with `maxConcurrent: 1` that key stays wedged **for
|
|
84
|
+
every replica** — indefinitely, because each new request refreshes the key's
|
|
85
|
+
TTL.
|
|
86
|
+
|
|
87
|
+
Set `expiration` above the slowest throttled handler, or `null` to disable it.
|
|
88
|
+
A job that overruns is rejected with a `BottleneckError` and its slot is
|
|
89
|
+
freed; the handler itself keeps running, Bottleneck just stops waiting for it.
|
|
90
|
+
|
|
91
|
+
Set it through this module's options or `@ConfigBottleneckDecorator()`, never
|
|
92
|
+
through raw Bottleneck `ConstructorOptions` — Bottleneck reads `expiration`
|
|
93
|
+
only from its job defaults, so it is silently ignored there.
|
|
94
|
+
|
|
55
95
|
## Throttling HTTP routes
|
|
56
96
|
|
|
57
97
|
`BottleneckInterceptor` runs on every HTTP request but only queues one that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bottleneck.interceptor.d.ts","sourceRoot":"","sources":["../../src/interceptors/bottleneck.interceptor.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,gBAAgB,EAIhB,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC,OAAO,EAEL,uBAAuB,EACxB,MAAM,4CAA4C,CAAC;AAUpD,qBACa,qBAAsB,YAAW,eAAe;IAKzD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkD;gBAItD,OAAO,EAAE,uBAAuB,EAChC,iBAAiB,EAAE,iBAAiB,EACpC,SAAS,EAAE,SAAS;IAQvC,SAAS,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW;
|
|
1
|
+
{"version":3,"file":"bottleneck.interceptor.d.ts","sourceRoot":"","sources":["../../src/interceptors/bottleneck.interceptor.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,gBAAgB,EAIhB,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC,OAAO,EAEL,uBAAuB,EACxB,MAAM,4CAA4C,CAAC;AAUpD,qBACa,qBAAsB,YAAW,eAAe;IAKzD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkD;gBAItD,OAAO,EAAE,uBAAuB,EAChC,iBAAiB,EAAE,iBAAiB,EACpC,SAAS,EAAE,SAAS;IAQvC,SAAS,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW;CAyGnD"}
|
|
@@ -63,9 +63,14 @@ let BottleneckInterceptor = BottleneckInterceptor_1 = class BottleneckIntercepto
|
|
|
63
63
|
return (0, rxjs_1.from)(this.bottleneckService
|
|
64
64
|
.scheduleForKey(key, async () => (0, rxjs_1.lastValueFrom)(next.handle()), bottleneckOptions)
|
|
65
65
|
.catch((err) => {
|
|
66
|
-
|
|
66
|
+
const message = String(err?.message || '');
|
|
67
|
+
if (message.includes('This limiter is at max capacity')) {
|
|
67
68
|
throw new common_1.ServiceUnavailableException('Too many requests queued for this order. Try again soon.');
|
|
68
69
|
}
|
|
70
|
+
if (message.includes('This job timed out after')) {
|
|
71
|
+
this.logger.warn(`⏱️ [Bottleneck] Job outran its expiration for key="${key}" method=${method} url=${url}; the handler is still running`);
|
|
72
|
+
throw new common_1.ServiceUnavailableException('This request took too long to complete. Check its result before retrying.');
|
|
73
|
+
}
|
|
69
74
|
throw err;
|
|
70
75
|
})
|
|
71
76
|
.finally(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bottleneck.interceptor.js","sourceRoot":"","sources":["../../src/interceptors/bottleneck.interceptor.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"bottleneck.interceptor.js","sourceRoot":"","sources":["../../src/interceptors/bottleneck.interceptor.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,7 @@ export interface BottleneckModuleOptions {
|
|
|
19
19
|
reservoirIncreaseAmount?: number | null;
|
|
20
20
|
reservoirIncreaseInterval?: number | null;
|
|
21
21
|
reservoirIncreaseMaximum?: number | null;
|
|
22
|
+
expiration?: number | null;
|
|
22
23
|
rejectOnDrop?: boolean | null;
|
|
23
24
|
trackDoneStatus?: boolean | null;
|
|
24
25
|
useRedis?: boolean;
|
|
@@ -30,6 +31,7 @@ export interface BottleneckModuleOptions {
|
|
|
30
31
|
database?: number;
|
|
31
32
|
ttl?: number;
|
|
32
33
|
tls?: boolean;
|
|
34
|
+
maxRetriesPerRequest?: number;
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
37
|
export interface BottleneckModuleFactory {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bottleneck-options.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/bottleneck-options.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtD,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AAOrE,MAAM,WAAW,uBAAuB;IAEtC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAOlB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAEjE,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"bottleneck-options.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/bottleneck-options.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtD,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AAOrE,MAAM,WAAW,uBAAuB;IAEtC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAOlB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAEjE,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAWzC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,OAAO,CAAC;QAQd,oBAAoB,CAAC,EAAE,MAAM,CAAC;KAC/B,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MACnB,OAAO,CAAC,uBAAuB,CAAC,GAAG,uBAAuB,CAAC;CAC9D;AAED,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CACxD,cAAc,EACd,SAAS,CACV;IACC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,QAAQ,CAAC,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC5C,UAAU,CAAC,EAAE,CACX,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,OAAO,CAAC,uBAAuB,CAAC,GAAG,uBAAuB,CAAC;CACjE"}
|
|
@@ -6,10 +6,16 @@ export declare class BottleneckService implements OnModuleDestroy {
|
|
|
6
6
|
private readonly logger;
|
|
7
7
|
private readonly group;
|
|
8
8
|
private readonly cache;
|
|
9
|
+
private readonly usesRedis;
|
|
10
|
+
private readonly expiration;
|
|
11
|
+
private bypassRedisUntil;
|
|
9
12
|
constructor(options: BottleneckModuleOptions);
|
|
10
13
|
private getLimiter;
|
|
11
|
-
private
|
|
14
|
+
private isStaleLimiterError;
|
|
15
|
+
private isRedisUnavailableError;
|
|
16
|
+
private jobOptions;
|
|
12
17
|
private scheduleWithSettingsRecovery;
|
|
18
|
+
private bypassRedis;
|
|
13
19
|
scheduleForKey<T>(key: string, task: () => Promise<T>, opts?: Bottleneck.ConstructorOptions): Promise<T>;
|
|
14
20
|
runQueuedTask<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
15
21
|
onModuleDestroy(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bottleneck.service.d.ts","sourceRoot":"","sources":["../../src/services/bottleneck.service.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAEL,uBAAuB,EACxB,MAAM,4CAA4C,CAAC;
|
|
1
|
+
{"version":3,"file":"bottleneck.service.d.ts","sourceRoot":"","sources":["../../src/services/bottleneck.service.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAEL,uBAAuB,EACxB,MAAM,4CAA4C,CAAC;AA6FpD,qBACa,iBAAkB,YAAW,eAAe;IAerD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAd1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAEpB;IACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAI3C,OAAO,CAAC,gBAAgB,CAAK;gBAIV,OAAO,EAAE,uBAAuB;YAwDrC,UAAU;IA0BxB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,UAAU;YAMJ,4BAA4B;IAkD1C,OAAO,CAAC,WAAW;IAgBb,cAAc,CAAC,CAAC,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACtB,IAAI,CAAC,EAAE,UAAU,CAAC,kBAAkB,GACnC,OAAO,CAAC,CAAC,CAAC;IAWP,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAmB/D,eAAe;CAGtB"}
|
|
@@ -21,6 +21,28 @@ const common_1 = require("@nestjs/common");
|
|
|
21
21
|
const bottleneck_1 = __importDefault(require("bottleneck"));
|
|
22
22
|
const bottleneck_options_interface_1 = require("../interfaces/bottleneck-options.interface");
|
|
23
23
|
const ioredis_1 = __importDefault(require("ioredis"));
|
|
24
|
+
const REDIS_RECOVERY_SIGNAL = /^ERR (UNKNOWN_CLIENT|SETTINGS_KEY_NOT_FOUND)$/;
|
|
25
|
+
const REDIS_UNAVAILABLE = /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|EHOSTUNREACH|EPIPE|Connection is closed|Stream isn't writeable|max retries per request|Command timed out|Connection is already closed/i;
|
|
26
|
+
const REDIS_BYPASS_MS = 5_000;
|
|
27
|
+
const REDIS_NOT_WRITABLE = /^(READONLY|LOADING|OOM|CLUSTERDOWN|MISCONF|TRYAGAIN|NOREPLICAS)\b/;
|
|
28
|
+
const DEFAULT_MAX_RETRIES_PER_REQUEST = 2;
|
|
29
|
+
const DEFAULT_EXPIRATION_MS = 60_000;
|
|
30
|
+
class BottleneckRedis extends ioredis_1.default {
|
|
31
|
+
sendCommand(...args) {
|
|
32
|
+
const [command] = args;
|
|
33
|
+
const reject = command?.reject;
|
|
34
|
+
if (typeof reject === 'function') {
|
|
35
|
+
command.reject = (error) => {
|
|
36
|
+
if (error instanceof Error &&
|
|
37
|
+
REDIS_RECOVERY_SIGNAL.test(error.message)) {
|
|
38
|
+
error.message = error.message.slice(4);
|
|
39
|
+
}
|
|
40
|
+
reject.call(command, error);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return super.sendCommand(...args);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
24
46
|
let BottleneckService = BottleneckService_1 = class BottleneckService {
|
|
25
47
|
constructor(options) {
|
|
26
48
|
this.options = options;
|
|
@@ -28,11 +50,12 @@ let BottleneckService = BottleneckService_1 = class BottleneckService {
|
|
|
28
50
|
timestamp: true,
|
|
29
51
|
});
|
|
30
52
|
this.cache = new Map();
|
|
31
|
-
|
|
53
|
+
this.bypassRedisUntil = 0;
|
|
54
|
+
const { useRedis, redis, appName, clearDatastore = false, expiration, ...rest } = this.options;
|
|
32
55
|
const redisOptions = useRedis && redis
|
|
33
56
|
? {
|
|
34
57
|
datastore: 'ioredis',
|
|
35
|
-
Redis:
|
|
58
|
+
Redis: BottleneckRedis,
|
|
36
59
|
clientOptions: {
|
|
37
60
|
host: redis.host,
|
|
38
61
|
port: redis.port,
|
|
@@ -40,6 +63,7 @@ let BottleneckService = BottleneckService_1 = class BottleneckService {
|
|
|
40
63
|
password: redis.password,
|
|
41
64
|
db: redis.database,
|
|
42
65
|
tls: redis.tls ? {} : undefined,
|
|
66
|
+
maxRetriesPerRequest: redis.maxRetriesPerRequest ?? DEFAULT_MAX_RETRIES_PER_REQUEST,
|
|
43
67
|
},
|
|
44
68
|
timeout: redis.ttl,
|
|
45
69
|
}
|
|
@@ -52,6 +76,11 @@ let BottleneckService = BottleneckService_1 = class BottleneckService {
|
|
|
52
76
|
...redisOptions,
|
|
53
77
|
...rest,
|
|
54
78
|
});
|
|
79
|
+
this.expiration = expiration === undefined ? DEFAULT_EXPIRATION_MS : expiration;
|
|
80
|
+
this.usesRedis = Boolean(redisOptions);
|
|
81
|
+
if (this.usesRedis) {
|
|
82
|
+
this.group.on('error', (error) => this.logger.error('Bottleneck datastore error', error instanceof Error ? error.stack : String(error)));
|
|
83
|
+
}
|
|
55
84
|
}
|
|
56
85
|
async getLimiter(key, opts) {
|
|
57
86
|
const limiter = this.group.key(key);
|
|
@@ -61,24 +90,67 @@ let BottleneckService = BottleneckService_1 = class BottleneckService {
|
|
|
61
90
|
}
|
|
62
91
|
return limiter;
|
|
63
92
|
}
|
|
64
|
-
|
|
93
|
+
isStaleLimiterError(error) {
|
|
65
94
|
return (error instanceof Error &&
|
|
66
|
-
/(?:^|\s)SETTINGS_KEY_NOT_FOUND$/.test(error.message));
|
|
95
|
+
/(?:^|\s)(SETTINGS_KEY_NOT_FOUND|UNKNOWN_CLIENT)$/.test(error.message));
|
|
96
|
+
}
|
|
97
|
+
isRedisUnavailableError(error) {
|
|
98
|
+
if (!(error instanceof Error))
|
|
99
|
+
return false;
|
|
100
|
+
const code = error.code;
|
|
101
|
+
return (REDIS_UNAVAILABLE.test(error.message) ||
|
|
102
|
+
REDIS_NOT_WRITABLE.test(error.message) ||
|
|
103
|
+
(code !== undefined && REDIS_UNAVAILABLE.test(code)));
|
|
104
|
+
}
|
|
105
|
+
jobOptions(opts) {
|
|
106
|
+
const expiration = opts?.expiration === undefined ? this.expiration : opts.expiration;
|
|
107
|
+
return expiration === null ? {} : { expiration };
|
|
67
108
|
}
|
|
68
109
|
async scheduleWithSettingsRecovery(key, task, opts) {
|
|
110
|
+
if (this.usesRedis && Date.now() < this.bypassRedisUntil) {
|
|
111
|
+
this.logger.debug(`Running key ${key} unthrottled; Redis still down`);
|
|
112
|
+
return task();
|
|
113
|
+
}
|
|
114
|
+
let taskStarted = false;
|
|
115
|
+
const guardedTask = () => {
|
|
116
|
+
taskStarted = true;
|
|
117
|
+
return task();
|
|
118
|
+
};
|
|
69
119
|
try {
|
|
70
120
|
const limiter = await this.getLimiter(key, opts);
|
|
71
|
-
return await limiter.schedule(
|
|
121
|
+
return await limiter.schedule(this.jobOptions(opts), guardedTask);
|
|
72
122
|
}
|
|
73
123
|
catch (error) {
|
|
74
|
-
if (
|
|
124
|
+
if (taskStarted)
|
|
75
125
|
throw error;
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
126
|
+
if (this.usesRedis && this.isRedisUnavailableError(error)) {
|
|
127
|
+
return this.bypassRedis(key, error, task);
|
|
128
|
+
}
|
|
129
|
+
if (!this.isStaleLimiterError(error))
|
|
130
|
+
throw error;
|
|
131
|
+
this.logger.warn(`Recreating limiter for key ${key} after its Redis state went stale: ${error.message}`);
|
|
132
|
+
let retryStarted = false;
|
|
133
|
+
try {
|
|
134
|
+
await this.group.deleteKey(key);
|
|
135
|
+
const limiter = await this.getLimiter(key, opts);
|
|
136
|
+
return await limiter.schedule(this.jobOptions(opts), () => {
|
|
137
|
+
retryStarted = true;
|
|
138
|
+
return task();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch (retryError) {
|
|
142
|
+
if (retryStarted || !this.isRedisUnavailableError(retryError)) {
|
|
143
|
+
throw retryError;
|
|
144
|
+
}
|
|
145
|
+
return this.bypassRedis(key, retryError, task);
|
|
146
|
+
}
|
|
80
147
|
}
|
|
81
148
|
}
|
|
149
|
+
bypassRedis(key, error, task) {
|
|
150
|
+
this.bypassRedisUntil = Date.now() + REDIS_BYPASS_MS;
|
|
151
|
+
this.logger.error(`Redis unavailable; running tasks unthrottled for the next ${REDIS_BYPASS_MS}ms (key ${key})`, error instanceof Error ? error.stack : String(error));
|
|
152
|
+
return task();
|
|
153
|
+
}
|
|
82
154
|
async scheduleForKey(key, task, opts) {
|
|
83
155
|
this.logger.debug(`Scheduling task for key ${key}`);
|
|
84
156
|
return this.scheduleWithSettingsRecovery(key, task, opts);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bottleneck.service.js","sourceRoot":"","sources":["../../src/services/bottleneck.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AACA,2CAA6E;AAC7E,4DAAoC;AACpC,6FAGoD;AACpD,sDAA4B;
|
|
1
|
+
{"version":3,"file":"bottleneck.service.js","sourceRoot":"","sources":["../../src/services/bottleneck.service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mondart/nestjs-common-module-bottleneck",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.13",
|
|
4
4
|
"description": "Bottleneck throttling and queue utilities for NestJS.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mondart"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"build": "tsc -p tsconfig.json"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@mondart/nestjs-common-module-core": "3.2.
|
|
20
|
+
"@mondart/nestjs-common-module-core": "3.2.11",
|
|
21
21
|
"@nestjs/cqrs": "^11.0.1",
|
|
22
22
|
"bottleneck": "^2.19.5",
|
|
23
23
|
"ioredis": "^5.11.1"
|