Open-source project
FabrizioBrancati/Queuer avatar
FabrizioBrancati/Queuer

Queuer: a Swift queue manager that adds retries and schedulers to OperationQueue

Queuer is a queue manager, built on top of OperationQueue and Dispatch (aka GCD).

1,148 stars46 forksSwiftMIT

At a glance

What is it?
Queuer wraps Foundation's OperationQueue and Dispatch to give Swift developers concurrent operation limits, chained and group operations, semaphores, schedulers, manual and automatic retries, and async and await support. Version 4.0.0 moved to Swift 6 strict concurrency, which is the real reason to look at it now.
Who is it for?
Queuer fits a Swift team that already uses OperationQueue, wants retries, semaphores and schedulers without writing its own subclasses, and is prepared to track the compatibility table when a platform floor moves. It does not fit a project that wants a queue with no dependency on Foundation's operation machinery, or one that cannot move to an older Queuer line for its platform floor.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 116 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • FabrizioBrancati/Queuer1,148 ★ · -2
Star history
Repository2026-10-192026-11-07
FabrizioBrancati/Queuer1.2k1.1k

-2 Stars in the last 19 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

A thin layer over OperationQueue, not a replacement for it

Queuer is described plainly as a queue manager built on top of OperationQueue and Dispatch, which is also known as GCD. That framing matters, because it means Queuer is not a new concurrency runtime. It is a convenience layer that sits over primitives Apple already ships, and the operations you create are ordinary `Operation` values that the underlying OperationQueue knows how to schedule.

The problem it solves is narrow and real. Foundation gives you a queue that runs operations, but it does not give you a readable way to chain a sequence of work, a scheduler, a semaphore, or a retry policy that survives a thrown error. Queuer collects those into one API surface with a shared instance or a named custom queue, and it advertises itself as fully documented with 100 percent of code coverage as its test suite.

It also targets more than Apple platforms. The feature list claims it works on all Swift compatible platforms, Linux, Android and Windows included, and the compatibility table marks Linux for every version of the library.

Concurrency limits live in one initializer argument

The central design decision is that the queue object itself carries the scheduling policy. You can use the shared instance if a single centralized queue is enough, and the documentation shows a one line call for that case:

swift
Queuer.shared.addOperation(operation)

Or you can create a named queue, and optionally hand it the two properties that determine how it behaves under load:

swift
let queue = Queuer(name: "MyCustomQueue", maxConcurrentOperationCount: Int.max, qualityOfService: .default)

`maxConcurrentOperationCount` is the knob that answers the question most teams actually have, which is how many of these operations may be in flight at once. Passing `Int.max` removes the limit, and `qualityOfService` sets the dispatch priority. The library also documents unlimited queues, so the constraint is not on the number of queue objects but on the concurrency inside each one.

That last point is where the design can bite. Multiple queues with unbounded concurrency each do not add up to a global limit, so a project that creates one queue per feature area can end up with far more work in flight than it intended. The concurrency declaration is per queue, and nothing in the documented API suggests a global cap.

Chains, groups and blocks for the common shapes of work

Queuer covers three ways of expressing work. The first is a block added directly to a queue, which is the shortest form and the one you will use most:

swift
queue.addOperation {
    /// Your task here
}

The second is an explicit `ConcurrentOperation` object, which is what you reach for when you need to hold a reference to the operation, cancel it, or inspect its state:

swift
let concurrentOperation = ConcurrentOperation { _ in
    /// Your task here
}
queue.addOperation(concurrentOperation)

The third is chaining, where operations add a dependency on each other and run in the order of the array you provide. The documentation also lists group operations for fanning work out and joining it back, and a separate section on a custom operation class for cases where the built-in types are not enough.

The API surface is broad enough that a queue library like this tends to grow into a framework. The documented usage list runs to more than a dozen sections, covering queue states, operation states, a synchronous queue variant, a scheduler, a semaphore, syntactic sugar for creating and chaining operations, and separate paths for async operations and async tasks inside an operation. That breadth is the main reason to read the source before picking it up.

Retries, throttled retries and manual finish as a safety net

The feature that distinguishes Queuer from a thin OperationQueue wrapper is its handling of failure. There is a section for automatically retrying an operation, a separate section for throttling automatic retries so a failing operation does not hammer a dependency in a tight loop, a section for manually retrying an operation, and another for manually finishing one.

Manual finish is the unusual one. An operation can be closed out by hand rather than by its own completion, which matters when the work is tracked by something outside the operation, such as a request whose response arrives on a different callback path.

Version 4.0.0, tagged on 2026-07-15 with the name Await Queuer, extends this to the async world. The feature list credits async and await operations with automatic retries on thrown errors, so a failing `async` call can be retried without you writing a loop. The same version builds in the Swift 6 language mode with strict concurrency, which is a genuine change in nature rather than a feature addition, since the operation types now have to satisfy the compiler's concurrency checking.

Schedulers and semaphores, and the OS floors they imply

Queuer adds a scheduler for recurring or delayed work and a semaphore for counting access. Both are listed as first class features with their own usage sections, and both sit on top of Foundation rather than replacing it.

The catch is the compatibility table. Queuer 4.0.0 requires Swift 5.9 through 6.3 and raises the floor to iOS 12, macOS 10.13, tvOS 12, watchOS 4, and adds macCatalyst 13, visionOS 1, plus Android and Windows. Some individual APIs ask for more than that: `AsyncConcurrentOperation`, `addChainedAsyncOperations(_:completionHandler:)`, `addAsyncCompletionHandler(_:)`, `addBarrier(_:)` and `barrier(_:)` require macOS 10.15, iOS 13, tvOS 13 or watchOS 6, and `asyncWait(_:tolerance:clock:)` requires macOS 13, iOS 16, tvOS 16 or watchOS 9.

On Linux, Android and Windows every API is always available. That asymmetry is worth noticing. The scheduler and semaphore are portable, while the newest async helpers are not, so a cross platform codebase will compile them behind availability checks that the library does not wrap for you.

Adding the package and running the test suite

Queuer ships as a Swift Package Manager package and is indexed on Swift Package Index. Adding it means adding the dependency in your `Package.swift` manifest:

swift
.package(url: "https://github.com/FabrizioBrancati/Queuer.git", from: "4.0.0"),

And then referencing the product from the targets that need it:

swift
.target(
    name: "MyTarget", 
    dependencies: [
        .product(name: "Queuer", package: "Queuer"),
    ]
),

The repository ships a Makefile that wraps the common chores. Resolving dependencies, building, testing and linting are all one make target, and the lint target uses swift-format with the configuration file in the repository root:

bash
swift package resolve
swift test
swift build

Two files in the repository root are worth knowing about if you plan to contribute. There is a `[email protected]` alongside the main `Package.swift`, which is how Swift Package Manager handles a manifest that differs by tools version, and a `Package.resolved` that pins the dependency versions used in development. There is also a pre-commit hook installer target, and a `make setup` target that chains clean, hook installation and dependency resolution.

Where Queuer stops being the right answer

The clearest boundary is the compatibility table itself. Queuer 4.0.0 needs Swift 5.9 or later and iOS 12, so a project still on Swift 4.x or targeting iOS 8 has to stay on an older line of the library, and the mapping between Swift versions and Queuer versions changes the deployment floor each time. Any project that must support macCatalyst, watchOS or visionOS has to check which Queuer version first introduced those columns.

The second limit is conceptual. A queue library that offers a shared instance, unlimited custom queues, group operations, semaphores and schedulers is a lot of machinery for a job that Foundation already partly covers. If all a service needs is a bounded worker pool and a retry, the value of Queuer is thinner than it looks, and each additional feature is another API you inherit and must maintain across Swift versions.

The third limit is that retry policy lives in a library rather than in your service. Automatic retry with throttling is convenient until the failure is a permanent one, such as a validation error, and the library's notion of retryable is not documented in detail. The same applies to strict concurrency: building in the Swift 6 language mode makes Queuer's own types more demanding to use correctly, and the migration burden lands on the caller rather than the library.

Editorial conclusion

Queuer fits a Swift team that already uses OperationQueue, wants retries, semaphores and schedulers without writing its own subclasses, and is prepared to track the compatibility table when a platform floor moves. It does not fit a project that wants a queue with no dependency on Foundation's operation machinery, or one that cannot move to an older Queuer line for its platform floor. Before adopting it, check three things: that your Swift toolchain is 5.9 or later for the 4.0.0 line, whether the APIs you need sit behind the newer OS requirements such as asyncWait requiring macOS 13, and whether the automatic retry and throttle settings match how your failing operations actually fail.

Frequently asked questions

What Swift version does Queuer 4.0.0 require?

Queuer 4.0.0 supports Swift 5.9 through 6.3 and raises the minimum to iOS 12, macOS 10.13, tvOS 12 and watchOS 4. Older Swift versions need an older Queuer line.

How do I limit how many operations run at once in Queuer?

Pass maxConcurrentOperationCount when you create the queue, for example Queuer(name: "MyCustomQueue", maxConcurrentOperationCount: Int.max, qualityOfService: .default). The limit applies per queue.

Does Queuer support Linux and Windows?

Yes, the feature list states it works on all Swift compatible platforms, Linux, Android and Windows included, and every API is always available on those three platforms regardless of OS version requirements.

Can Queuer retry an operation automatically?

Yes, there are sections for automatic retry and for throttling automatic retries, plus manual retry and manual finish. Version 4.0.0 adds automatic retries on thrown errors for async and await operations.

How do I add Queuer to a Swift project?

Add .package(url: "https://github.com/FabrizioBrancati/Queuer.git", from: "4.0.0") to the dependencies argument of your Package.swift manifest, then add .product(name: "Queuer", package: "Queuer") to the dependencies of each target that uses it.

Official sources

  1. FabrizioBrancati/Queuer on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fabriziobrancati-queuer.svg)](https://hysenlabs.com/projects/fabriziobrancati-queuer)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/fabriziobrancati-queuer.svg)](https://hysenlabs.com/projects/fabriziobrancati-queuer)

Was this useful?