uppy/packages/@uppy/utils
Merlijn Vos 6b1abaa541
@uppy/utils,@uppy/xhr-upload: create and use new queue (#6105)
Closes #4173, kind off

## Problem

Current situation with `RateLimitedQueue`

- Track concurrency: keep a running count, only dispatch up to limit,
accept Infinity.
- Priority enqueue: queued handlers sorted by priority; dequeued in that
order.
- Lifecycle bookkeeping: each job gets abort()/done() hooks; abort for
running vs queued differs; decrement active count and advance queue via
microtasks.
- Requeue placeholders: supports a shouldBeRequeued marker so callers
can hold/retry slots without running immediately.
- Function wrappers: wrap sync or async fns to enforce the queue and
return abortable handles.
- Cancellation plumbing: provides abortOn(signal) to bind queued/running
work to an AbortSignal; abortable promises carry abort().
- Pausing: pause(duration?) freezes dispatch (optional auto-resume);
resume() restarts up to the current limit.
- Rate limiting/backoff: rateLimit(duration) pauses, drops concurrency,
then ramps it back toward the previous upper bound over time.

Case in point: it's some sort of made up, monstrosity data structure
trying to be too many things. It also has rate limiting and exponential
backoff but that's already in
[`fetcher`](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/utils/src/fetcher.ts)
too.

Would be better if we had separation of concerns and proven data
structures.

## Solution

A "dumb" promise-based priority queue that doesn't care at all about
what a promise does or if it needs to be retried. The promise inside
determines if it has retrying and exponential backoff, such as a
`fetcher` promise.

To not make this a breaking change and a huge diff, we still implement
this per uploader, starting with xhr-upload, and keep backwards
compatibility in the interface so we can still pass it to
`companion-client`, which needs to share the same queue.

## Ideal future

When you think about it, it's odd that we implement a queue per uploader
if a queue is so central to uppy working correctly. It's even more odd
that we also have to inject that queue into `companion-client` per
uploader for queue sharing.

Ideally, `core` is responsible for having the queue. All uploaders would
do is push a promise to `core` and `core` doesn't care if that promise
is a tus, xhr, or S3 upload.

---------

Co-authored-by: Prakash <qxprakash@gmail.com>
2026-02-05 15:46:45 +01:00
..
src @uppy/utils,@uppy/xhr-upload: create and use new queue (#6105) 2026-02-05 15:46:45 +01:00
.npmignore meta: exclude tsconfig files from npm bundles (#4916) 2024-02-13 23:21:08 +01:00
CHANGELOG.md [ci] release (#6096) 2025-12-09 10:01:30 +01:00
LICENSE Add @uppy/utils skeleton. 2018-06-14 16:31:19 +02:00
package.json build(deps): bump lodash from 4.17.21 to 4.17.23 (#6152) 2026-01-26 15:01:18 +01:00
README.md Fix links (#5492) 2024-10-29 13:54:00 +01:00
tsconfig.build.json Remove preact/compat (#5935) 2025-08-28 16:57:07 +02:00
tsconfig.json Remove preact/compat (#5935) 2025-08-28 16:57:07 +02:00

@uppy/utils

Uppy logo: a smiling puppy above a pink upwards arrow

npm version CI status for Uppy tests CI status for Companion tests CI status for browser tests

Shared utility functions for Uppy Core and the “official” plugins maintained by the Uppy team.

Uppy is being developed by the folks at Transloadit, a versatile file encoding service.

Installation

Unless you are creating a custom plugin, you should not need to install this manually.

$ npm install @uppy/utils

License

The MIT License.