{"id":937,"url":"https://github.com/FabrizioBrancati/Queuer","last_synced_at":"2025-08-06T13:31:54.508Z","repository":{"id":46139712,"uuid":"97841572","full_name":"FabrizioBrancati/Queuer","owner":"FabrizioBrancati","description":"Queuer is a queue manager, built on top of OperationQueue and Dispatch (aka GCD).","archived":false,"fork":false,"pushed_at":"2025-06-09T19:20:38.000Z","size":992,"stargazers_count":1157,"open_issues_count":5,"forks_count":48,"subscribers_count":20,"default_branch":"main","last_synced_at":"2025-06-30T11:07:12.432Z","etag":null,"topics":["async-await","asynchronous","asynchronous-tasks","carthage","dispatch","foundation","grand-central-dispatch","linux","macos","operation","operationqueue","queuer","scheduler","semaphore","swift","swift-package-manager","synchronous-tasks","task","tvos","watchos"],"latest_commit_sha":null,"homepage":"https://swiftpackageindex.com/FabrizioBrancati/Queuer","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FabrizioBrancati.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-07-20T13:57:48.000Z","updated_at":"2025-06-27T04:58:18.000Z","dependencies_parsed_at":"2024-05-07T09:26:25.501Z","dependency_job_id":"dceeaedd-d480-432e-8789-856d884ccc1b","html_url":"https://github.com/FabrizioBrancati/Queuer","commit_stats":{"total_commits":362,"total_committers":2,"mean_commits":181.0,"dds":0.002762430939226568,"last_synced_commit":"4cc9f2317f57814f29af1834657d45beba0af030"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/FabrizioBrancati/Queuer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FabrizioBrancati%2FQueuer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FabrizioBrancati%2FQueuer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FabrizioBrancati%2FQueuer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FabrizioBrancati%2FQueuer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FabrizioBrancati","download_url":"https://codeload.github.com/FabrizioBrancati/Queuer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FabrizioBrancati%2FQueuer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268488192,"owners_count":24258235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-03T02:00:12.545Z","response_time":2577,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-await","asynchronous","asynchronous-tasks","carthage","dispatch","foundation","grand-central-dispatch","linux","macos","operation","operationqueue","queuer","scheduler","semaphore","swift","swift-package-manager","synchronous-tasks","task","tvos","watchos"],"created_at":"2024-01-05T20:15:35.028Z","updated_at":"2025-08-06T13:31:54.220Z","avatar_url":"https://github.com/FabrizioBrancati.png","language":"Swift","funding_links":[],"categories":["Concurrency","Libs","Swift","HarmonyOS","Architecture and State","Concurrency [🔝](#readme)"],"sub_categories":["Linter","Concurrency","Other free courses","Windows Manager"],"readme":"# Queuer\n\n[![GitHub Release](https://img.shields.io/github/v/release/FabrizioBrancati/Queuer?label=Release)](https://swiftpackageindex.com/FabrizioBrancati/Queuer)\n[![Swift Versions](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FFabrizioBrancati%2FQueuer%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/FabrizioBrancati/Queuer)\n[![Swift Platforms](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FFabrizioBrancati%2FQueuer%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/FabrizioBrancati/Queuer)\n\n## Features\n\nQueuer is a queue manager, built on top of [OperationQueue](https://developer.apple.com/documentation/foundation/operationqueue) and [Dispatch](https://developer.apple.com/documentation/dispatch) (aka GCD). It allows you to create any asynchronous and synchronous task easily, all managed by a queue, with just a few lines.\n\nHere is the list of all the features:\n\n- [x] Works on all Swift compatible platforms (even Linux)\n- [x] Easy to use\n- [x] Well documented (100% documented)\n- [x] Well tested (100% of code coverage)\n- [x] Create an operation block\n- [x] Create a single operation\n- [x] Create chained operations\n- [x] Manage a centralized queue\n- [x] Create unlimited queue\n- [x] Declare how many concurrent operation a queue can handle\n- [x] Create semaphores\n- [x] Create and handle schedules\n- [x] Automatically or manually retry an operation\n- [ ] Throttling between each automatic operation retry\n\n## Requirements\n\n| **Swift**  | **Queuer**    | **iOS** | **macOS**  | **macCatalyst** | **tvOS**  | **watchOS** | **visionOS** | **Linux** |\n|------------|---------------|---------|------------|-----------------|-----------|-------------|--------------|-----------|\n| 3.1...3.2  | 1.0.0...1.1.0 | 8.0+    | 10.10+     |                 | 9.0+      | 2.0+        |              | ✅        |\n| 4.0        | 1.3.0         | 8.0+    | 10.10+     |                 | 9.0+      | 2.0+        |              | ✅        |\n| 4.1        | 1.3.1...1.3.2 | 8.0+    | 10.10+     |                 | 9.0+      | 2.0+        |              | ✅        |\n| 4.2        | 2.0.0...2.0.1 | 8.0+    | 10.10+     |                 | 9.0+      | 3.0+        |              | ✅        |\n| 5.0...5.10 | 2.1.0...2.2.0 | 8.0+    | 10.10+     |                 | 9.0+      | 3.0+        |              | ✅        |\n| 5.9...5.10 | 3.0.0         | 12.0+   | 10.13+     | 13.0+           | 12.0+     | 4.0+        | 1.0+         | ✅        |\n\n## Installing\n\nSee [Requirements](https://github.com/FabrizioBrancati/Queuer#requirements) section to check Swift, Queuer, and OS versions.\n\nIn your `Package.swift` Swift Package Manager manifest, add the following dependency to your `dependencies` argument:\n\n```swift\n.package(url: \"https://github.com/FabrizioBrancati/Queuer.git\", from: \"3.0.0\"),\n```\n\nAdd the dependency to any targets you've declared in your manifest:\n\n```swift\n.target(\n    name: \"MyTarget\", \n    dependencies: [\n        .product(name: \"Queuer\", package: \"Queuer\"),\n    ]\n),\n```\n\n## Usage\n\n- [Shared Queuer](https://github.com/FabrizioBrancati/Queuer#shared-queuer)\n- [Custom Queue](https://github.com/FabrizioBrancati/Queuer#custom-queue)\n- [Create an Operation Block](https://github.com/FabrizioBrancati/Queuer#create-an-operation-block)\n- [Chained Operations](https://github.com/FabrizioBrancati/Queuer#chained-operations)\n- [Group Oprations](https://github.com/FabrizioBrancati/Queuer#group-operations)\n- [Queue States](https://github.com/FabrizioBrancati/Queuer#queue-states)\n- [Synchronous Queue](https://github.com/FabrizioBrancati/Queuer#synchronous-queue)\n- [Asynchronous Operation](https://github.com/FabrizioBrancati/Queuer#asynchronous-operation)\n- [Automatically Retry an Operation](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation)\n- [Manually Retry an Operation](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation)\n- [Manually Finish an Operation](https://github.com/FabrizioBrancati/Queuer#manually-finish-an-operation)\n- [Async Task in an Operation](https://github.com/FabrizioBrancati/Queuer#async-tasks-in-an-operation)\n- [Scheduler](https://github.com/FabrizioBrancati/Queuer#scheduler)\n- [Semaphore](https://github.com/FabrizioBrancati/Queuer#semaphore)\n\n### Shared Queuer\n\nQueuer offers a shared instance that you can use to add operations to a centralized queue:\n\n```swift\nQueuer.shared.addOperation(operation)\n```\n\n### Custom Queue\n\nYou can also create a custom queue:\n\n```swift\nlet queue = Queuer(name: \"MyCustomQueue\")\n```\n\nYou can even create a queue by defining the `maxConcurrentOperationCount` and the `qualityOfService` properties:\n\n```swift\nlet queue = Queuer(name: \"MyCustomQueue\", maxConcurrentOperationCount: Int.max, qualityOfService: .default)\n```\n\n### Create an Operation Block\n\nYou have three methods to add an `Operation` block.\n\n1. Directly on the `queue`(or `Queuer.shared`):\n\n    ```swift\n    queue.addOperation {\n        /// Your task here\n    }\n    ```\n\n2. Creating a `ConcurrentOperation` with a block:\n\n    ```swift\n    let concurrentOperation = ConcurrentOperation { _ in\n        /// Your task here\n    }\n    queue.addOperation(concurrentOperation)\n    ```\n\n\u003e [!NOTE]\n\u003e We will see how `ConcurrentOperation` works later.\n\n### Chained Operations\n\nChained Operations are `Operation`s that add a dependency each other.\n\nThey follow the given array order, for example: `[A, B, C] = A -\u003e B -\u003e C -\u003e completionBlock`.\n\n```swift\nlet concurrentOperationA = ConcurrentOperation { _ in\n    /// Your task A here\n}\nlet concurrentOperationB = ConcurrentOperation { _ in\n    /// Your task B here\n}\nqueue.addChainedOperations([concurrentOperationA, concurrentOperationB]) {\n    /// Your completion task here\n}\n```\n\nYou can also add a `completionHandler` after the queue creation with:\n\n```swift\nqueue.addCompletionHandler {\n    /// Your completion task here\n}\n```\n\n### Group Operations\n\nGroup Operations are `Operation`s that handles a group of `Operation`s with a completion handler.\n\nAllows the execution of a block of `Operation`s with a completion handler that will be called once all the operations are finished, for example: `[A -\u003e [[B \u0026 C \u0026 D] -\u003e completionHandler] -\u003e E] -\u003e completionHandler`.\nIt should usually be used with a [Chained Opetation](https://github.com/FabrizioBrancati/Queuer#chained-operations).\n\n```swift\nlet groupOperationA = GroupOperation(\n    [\n        ConcurrentOperation { _ in\n            /// Your task A here\n        },\n        ConcurrentOperation { _ in\n            /// Your task B here\n        }\n    ]\n)\n\nlet concurrentOperationC = ConcurrentOperation { _ in\n    /// Your task C here\n}\n\nqueue.addChainedOperations([groupOperationA, concurrentOperationC]) {\n    /// Your completion task here\n}\n```\n\nIn this case the output will be the following one: `[[A \u0026 B -\u003e completionHandler] -\u003e C] -\u003e completionHandler`.\n\n### Queue States\n\nThere are a few method to handle the queue states.\n\n1. Cancel all `Operation`s in a queue:\n\n    ```swift\n    queue.cancelAll()\n    ```\n\n2. Pause a queue:\n\n    ```swift\n    queue.pause()\n    ```\n\n\u003e [!WARNING]\n\u003e By calling `pause()` you will not be sure that every `Operation` will be paused. If the `Operation` is already started it will not be on pause until it's a custom `Operation` that overrides `pause()` function.\n\n3. Resume a queue:\n\n    ```swift\n    queue.resume()\n    ```\n\n\u003e [!WARNING]\n\u003e To have a complete `pause` and `resume` states you must create a custom `Operation` that overrides `pause()` and `resume()` function.\n\n4. Wait until all `Operation`s are finished:\n\n    ```swift\n    queue.waitUntilAllOperationsAreFinished()\n    ```\n\n\u003e [!IMPORTANT]\n\u003e This function means that the queue will blocks the current thread until all `Operation`s are finished.\n\n### Synchronous Queue\n\nSetting the `maxConcurrentOperationCount` property of a queue to `1` will make you sure that only one task at a time will be executed.\n\n### Asynchronous Operation\n\n`ConcurrentOperation` is a class created to be subclassed.\nIt allows synchronous and asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block.\n\nYou can create your custom `ConcurrentOperation` by subclassing it.\n\nYou must override `execute()` function and call the `finish(success:)` function inside it, when the task has finished its job to notify the queue.\n\nFor convenience it has an `init` function with a completion block:\n\n```swift\nlet concurrentOperation = ConcurrentOperation { _ in\n    /// Your task here\n}\nconcurrentOperation.addToQueue(queue)\n```\n\n### Automatically Retry an Operation\n\nAn `Operation` is passed to every closure, with it you can set and handle the retry feature.\n\nBy default the retry feature is disabled, to enable it simply set the `success` property to `false`. With `success` to `false` the `Operation` will retry until reaches `maximumRetries` property value. To let the `Operation` know when everything is ok, you must set `success` to `true`.\n\nWith `currentAttempt` you can know at which attempt the `Operation` is.\n\n```swift\nlet concurrentOperation = ConcurrentOperation { operation in\n    /// Your task here\n    if /* Successful */ {\n      operation.success = true\n    } else {\n      operation.success = false\n    }\n}\n```\n\n### Manually Retry an Operation\n\nYou can manually retry an `Operation` when you think that the execution will be successful.\n\nAn `Operation` is passed to every closure, with it you can set and handle the retry feature.\n\nBy default the manual retry feature is disabled, to enable it simply set the `manualRetry` property to `true`, you must do this outside of the execution closure. You must also set `success` to `true` or `false` to let the `Operation` know when is everything ok, like the automatic retry feature.\n\nTo let the `Operation` retry your execution closure, you have to call the `retry()` function. Be sure to call it at least `maximumRetries` times, it is not a problem if you call `retry()` more times than is needed, your execution closure will not be executed more times than the `maximumRetries` value.\n\n```swift\nlet concurrentOperation = ConcurrentOperation { operation in\n    /// Your task here\n    if /* Successful */ {\n      operation.success = true\n    } else {\n      operation.success = false\n    }\n}\nconcurrentOperation.manualRetry = true\n\n/// Later on your code\nconcurrentOperation.retry()\n```\n\n\u003e [!CAUTION]\n\u003e If the `retry()` function is not called, you may block the entire queue.\n\n### Manually Finish an Operation\n\nBy default the `Operation` will finish its job when the execution closure is completed.\n\nThis means, if you have an asynchronous task insiede the closure, the `Operation` will finish before the task is completed.\n\nIf you want to finish it manually, you can set the `manualFinish` property to `true` and call the `finish(success:)` function when the task is completed.\n\nCall the `finish(success:)` function with `success` parameter to `true` or `false` to let the `Operation` know if the task was successful or not. If you don't explicitly set the `success` parameter, it will be set to `true`.\n\n```swift\nlet concurrentOperation = ConcurrentOperation { operation in\n    /// Your asynchonous task here\n}\nconcurrentOperation.manualFinish = true\n\n/// Later on your code in your asynchronous task\nconcurrentOperation.finish(success: true)\n```\n\n\u003e [!CAUTION]\n\u003e If you don't call the `finish(success:)` function, your queue will be blocked and it will never ends.\n\n### Async Task in an Operation\n\nIf you want to use async/await tasks, you need to set `manualFinish` to `true` in order to be fully in control of the `Operation` lifecycle.\n\n\u003e [!NOTE]\n\u003e Read more about manually finish an `Operation` [here](https://github.com/FabrizioBrancati/Queuer#manually-finish-an-operation).\n\n```swift\nlet concurrentOperation = ConcurrentOperation { operation in\n    Task {\n        /// Your asynchonous task here\n        operation.finish(success: true) // or false\n    }\n    /// Your asynchonous task here\n}\nconcurrentOperation.manualFinish = true\n```\n\n\u003e [!CAUTION]\n\u003e If you don't set `manualFinish` to `true`, your `Operation` will finish before the async task is completed.\n\n### Scheduler\n\nA `Scheduler` is a struct that uses the GDC's `DispatchSourceTimer` to create a timer that can execute functions with a specified interval and quality of service.\n\n```swift\nlet schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) {\n    /// Your task here\n}\n```\n\nYou can even create a `Scheduler` without the handler and set it later:\n\n```swift\nvar schedule = Scheduler(deadline: .now(), repeating: .seconds(1))\nschedule.setHandler {\n    /// Your task here\n}\n```\n\nWith `timer` property you can access to all `DispatchSourceTimer` properties and functions, like `cancel()`:\n\n```swift\nschedule.timer.cancel()\n```\n\n### Semaphore\n\nA `Semaphore` is a struct that uses the GCD's `DispatchSemaphore` to create a semaphore on the function and wait until it finish its job.\n\n\u003e [!TIP]\n\u003e Is recommend to use a `defer { semaphore.continue() }` right after the `Semaphore` creation and `wait()` call.\n\n```swift\nlet semaphore = Semaphore()\nsemaphore.wait()\ndefer { semaphore.continue() }\n/// Your task here\n```\n\nYou can even set a custom timeout, default is `.distantFuture`:\n\n```swift\nsemaphore.wait(DispatchTime(uptimeNanoseconds: 1_000_000_000))\n```\n\nIt's more useful if used inside an asynchronous task:\n\n```swift\nlet concurrentOperation = ConcurrentOperation {\n    /// Your task here\n    semaphore.continue()\n}\nconcurrentOperation.addToQueue(queue)\nsemaphore.wait()\n```\n\n## Changelog\n\nTo see what has changed in recent versions of Queuer, see the **[CHANGELOG.md](https://github.com/FabrizioBrancati/Queuer/blob/main/CHANGELOG.md)** file.\n\n## Communication\n\n- If you need help, open an issue.\n- If you found a bug, open an issue.\n- If you have a feature request, open an issue.\n- If you want to contribute, see [Contributing](https://github.com/FabrizioBrancati/Queuer#contributing) section.\n\n## Contributing\n\nSee [CONTRIBUTING.md](https://github.com/FabrizioBrancati/Queuer/blob/main/.github/CONTRIBUTING.md) file.\n\n## License\n\nQueuer is available under the MIT license. See the **[LICENSE](https://github.com/FabrizioBrancati/Queuer/blob/main/LICENSE)** file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFabrizioBrancati%2FQueuer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFabrizioBrancati%2FQueuer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFabrizioBrancati%2FQueuer/lists"}