Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@
"expectTypeOf",
"assert",
"assertType",
"assert.**",
"**.noErrVal"
"assert.**"
]
}
]
Expand Down
50 changes: 21 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ More importantly, this library has been rewritten with modern-day JS (courtesy o

### Breaking changes in v4

- The callback-style `submit()` method has been removed — Bottleneck is now Promise-only. Use `schedule()`, wrapping callback-style functions with [`util.promisify`](https://nodejs.org/api/util.html#utilpromisifyoriginal). The `Bottleneck.Callback` type is gone from the typings.
- The ES5 build has been removed (`require("bottleneck/es5")` no longer exists). If you need broad-browser support, use the UMD `@sderrow/bottleneck/light` build instead.
- Cluster mode now requires `redis` v4+ (drops v2/v3) or `ioredis` v5+. The unsupported `redis` v2/v3 client API has been removed.
- `ioredis` and `redis` are now optional **peer dependencies**. Your application must install whichever client it uses.
Expand All @@ -35,7 +36,6 @@ See [Upgrading to v4](#upgrading-to-v4) for migration steps.
- [Gotchas & Common Mistakes](#gotchas--common-mistakes)
- [Constructor](#constructor)
- [Reservoir Intervals](#reservoir-intervals)
- [`submit()`](#submit)
- [`schedule()`](#schedule)
- [`wrap()`](#wrap)
- [Job Options](#job-options)
Expand Down Expand Up @@ -153,16 +153,11 @@ const result = await wrapped(arg1, arg2);

#### ➤ Using callbacks?

Instead of this:
Bottleneck is Promise-only. Wrap callback-style functions with [`util.promisify`](https://nodejs.org/api/util.html#utilpromisifyoriginal) and `schedule()` them:

```js
someAsyncCall(arg1, arg2, callback);
```

Do this:

```js
limiter.submit(someAsyncCall, arg1, arg2, callback);
const promisified = util.promisify(someAsyncCall);
const result = await limiter.schedule(promisified, arg1, arg2);
```

### Step 3 of 3
Expand Down Expand Up @@ -219,9 +214,7 @@ limiter.schedule(() => object.doSomething());

- If you plan on using `priorities`, make sure to set a `maxConcurrent` value.

- **When using `submit()`**, if a callback isn't necessary, you must pass `null` or an empty function instead. It will not work otherwise.

- **When using `submit()`**, make sure all the jobs will eventually complete by calling their callback, or set an [`expiration`](#job-options). Even if you submitted your job with a `null` callback , it still needs to call its callback. This is particularly important if you are using a `maxConcurrent` value that isn't `null` (unlimited), otherwise those not completed jobs will be clogging up the limiter and no new jobs will be allowed to run. It's safe to call the callback more than once, subsequent calls are ignored.
- **Make sure your jobs eventually settle** (resolve or reject), or set an [`expiration`](#job-options). With a `maxConcurrent` value that isn't `null` (unlimited), jobs whose promises never settle clog the limiter and no new jobs will be allowed to run.

- Using tools like `mockdate` in your tests to change time in JavaScript will likely result in undefined behavior from Bottleneck.

Expand Down Expand Up @@ -301,21 +294,9 @@ Reservoir Intervals are an advanced feature, please take the time to read and un

- **Reservoir Intervals prevent a limiter from being garbage collected.** Call `limiter.disconnect()` to clear the interval and allow the memory to be freed. However, it's not necessary to call `.disconnect()` to allow the Node.js process to exit.

### submit()

Adds a job to the queue. This is the callback version of `schedule()`.

```js
limiter.submit(someAsyncCall, arg1, arg2, callback);
```

You can pass `null` instead of an empty function if there is no callback, but `someAsyncCall` still needs to call **its** callback to let the limiter know it has completed its work.

`submit()` can also accept [advanced options](#job-options).

### schedule()

Adds a job to the queue. This is the Promise and async/await version of `submit()`.
Adds a job to the queue.

```js
const fn = function (arg1, arg2) {
Expand Down Expand Up @@ -360,12 +341,9 @@ wrapped()

### Job Options

`submit()`, `schedule()`, and `wrap()` all accept advanced options.
`schedule()` and `wrap()` accept advanced options.

```js
// Submit
limiter.submit({/* options */}, someAsyncCall, arg1, arg2, callback);

// Schedule
limiter.schedule({/* options */}, fn, arg1, arg2);

Expand Down Expand Up @@ -1123,6 +1101,20 @@ The same applies to `Bottleneck.Group` and to the standalone `Bottleneck.RedisCo

If you previously hit "Bottleneck failed to require ioredis at runtime", that workaround paragraph is no longer needed. The implicit-require hack has been removed entirely.

### `submit()` users

The callback API is gone. The one-line translation:

```js
// Before
limiter.submit(someAsyncCall, arg1, arg2, callback);

// After
limiter.schedule(util.promisify(someAsyncCall), arg1, arg2).then(result => /* ... */);
```

Job options move over unchanged: `limiter.schedule({ priority: 4 }, fn, ...args)`.

### Legacy `redis` v2/v3 users

The minimum supported `redis` package version is now v4. The v2/v3 callback-style client API is no longer supported. Follow node-redis's own [v3-to-v4 migration guide](https://github.com/redis/node-redis/blob/master/docs/v3-to-v4.md) to upgrade your client. v5 is also fully supported.
Expand Down
11 changes: 0 additions & 11 deletions bottleneck.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ declare module "bottleneck" {
*/
readonly enqueueErrorMessage?: string | null;
};
type Callback<T> = (err: any, result: T) => void;
type ClientsList = { client?: any; subscriber?: any };
type GroupLimiterPair = { key: string; limiter: Bottleneck };
type Strategy = number & { readonly __brand: "BottleneckStrategy" };
Expand Down Expand Up @@ -597,16 +596,6 @@ declare module "bottleneck" {
withOptions: (options: Bottleneck.JobOptions, ...args: Args) => Promise<R>;
};

submit<R, Args extends any[]>(
fn: (...args: [...Args, Bottleneck.Callback<R>]) => void,
...args: [...Args, Bottleneck.Callback<R>]
): void;
submit<R, Args extends any[]>(
options: Bottleneck.JobOptions,
fn: (...args: [...Args, Bottleneck.Callback<R>]) => void,
...args: [...Args, Bottleneck.Callback<R>]
): void;

schedule<R, Args extends any[]>(
fn: (...args: Args) => PromiseLike<R>,
...args: Args
Expand Down
43 changes: 0 additions & 43 deletions src/Bottleneck.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,49 +396,6 @@ class Bottleneck {
}
}

submit(...sargs) {
let cb, fn, options;
if (typeof sargs[0] === "function") {
cb = sargs.pop();
[fn, ...sargs] = sargs;
options = parser.load({}, this.jobDefaults);
} else {
cb = sargs.pop();
[options, fn, ...sargs] = sargs;
options = parser.load(options, this.jobDefaults);
}

const task = (...targs) => {
return new Promise((resolve, reject) =>
fn(...targs, (...args) => (args[0] != null ? reject : resolve)(args)),
);
};

const job = new Job(
task,
sargs,
options,
this.jobDefaults,
this.rejectOnDrop,
this.Events,
this._states,
);
// Promise-to-callback bridge for the dual submit()/schedule() API: submit()
// is synchronous and pipes the job's eventual outcome into the Node-style
// callback. The chain form IS the bridge — an async wrapper would just add
// a floating promise around the same pipe.
job.promise
.then((args) => (typeof cb === "function" ? cb(...(args || [])) : undefined))
.catch((args) => {
if (Array.isArray(args)) {
return typeof cb === "function" ? cb(...args) : undefined;
} else {
return typeof cb === "function" ? cb(args) : undefined;
}
});
return this._receive(job);
}

schedule(...args) {
let options, task;
if (typeof args[0] === "function") {
Expand Down
39 changes: 0 additions & 39 deletions test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ package name via the triple-slash reference above). Checked by
`pnpm tsc` as part of the project tsconfig.
*/

function withCb(foo: number, bar: () => void, cb: (err: any, result: string) => void) {
let s: string = `cb ${foo}`;
cb(null, s);
}

console.log(Bottleneck);

let limiter = new Bottleneck({
Expand Down Expand Up @@ -61,17 +56,6 @@ limiter.done().then(function (x) {
let i: number = x;
});

limiter.submit(
withCb,
1,
() => {},
(err, result) => {
let s: string = result;
console.log(s);
assert(s == "cb 1");
},
);

function withPromise(foo: number, bar: () => void): PromiseLike<string> {
let s: string = `promise ${foo}`;
return Promise.resolve(s);
Expand Down Expand Up @@ -185,29 +169,6 @@ group.on("created", (limiter, key) => {
assert(key.length > 0);
});

group.key("foo").submit(
withCb,
2,
() => {},
(err, result) => {
let s: string = `${result} foo`;
console.log(s);
assert(s == "cb 2 foo");
},
);

group.key("bar").submit(
{ priority: 4 },
withCb,
3,
() => {},
(err, result) => {
let s: string = `${result} bar`;
console.log(s);
assert(s == "cb 3 foo");
},
);

let f1: Promise<string> = group.key("pizza").schedule(withPromise, 2, () => {});
f1.then(function (result: string) {
let s: string = result;
Expand Down
Loading