{"id":22208264,"url":"https://github.com/ph1ps/swift-concurrency-deadline","last_synced_at":"2025-07-08T06:06:12.802Z","repository":{"id":253161653,"uuid":"842631640","full_name":"ph1ps/swift-concurrency-deadline","owner":"ph1ps","description":"A deadline algorithm for Swift Concurrency","archived":false,"fork":false,"pushed_at":"2025-04-27T13:48:58.000Z","size":56,"stargazers_count":54,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-08T06:03:12.497Z","etag":null,"topics":["concurrency","deadline","swift","swift-concurrency","timeout"],"latest_commit_sha":null,"homepage":"","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/ph1ps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":"2024-08-14T18:38:13.000Z","updated_at":"2025-06-17T10:57:29.000Z","dependencies_parsed_at":"2024-08-22T07:26:41.274Z","dependency_job_id":"193229f4-7c68-423b-ba17-a1b08f0ff677","html_url":"https://github.com/ph1ps/swift-concurrency-deadline","commit_stats":null,"previous_names":["ph1ps/swift-concurrency-deadline"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/ph1ps/swift-concurrency-deadline","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ph1ps%2Fswift-concurrency-deadline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ph1ps%2Fswift-concurrency-deadline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ph1ps%2Fswift-concurrency-deadline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ph1ps%2Fswift-concurrency-deadline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ph1ps","download_url":"https://codeload.github.com/ph1ps/swift-concurrency-deadline/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ph1ps%2Fswift-concurrency-deadline/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264206387,"owners_count":23572597,"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","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":["concurrency","deadline","swift","swift-concurrency","timeout"],"created_at":"2024-12-02T19:17:01.269Z","updated_at":"2025-07-08T06:06:12.796Z","avatar_url":"https://github.com/ph1ps.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Deadline\nA deadline algorithm for Swift Concurrency.\n\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fph1ps%2Fswift-concurrency-deadline%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/ph1ps/swift-concurrency-deadline)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fph1ps%2Fswift-concurrency-deadline%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/ph1ps/swift-concurrency-deadline)\n\n## Rationale\nAs I've previously stated on the [Swift forums](https://forums.swift.org/t/my-experience-with-concurrency/73197): in my opinion deadlines or timeouts are a missing piece in Swift's Concurrency system. Since this algorithm is not easy to get right I decided to open-source my implementation.\n\n## Details\n\nThe library comes with two free functions, one with a generic clock and another one which uses the `ContinuousClock` as default.\n```swift\npublic func deadline\u003cC, R\u003e(\n  until instant: C.Instant,\n  tolerance: C.Instant.Duration? = nil,\n  clock: C,\n  isolation: isolated (any Actor)? = #isolation,\n  operation: @Sendable () async throws -\u003e R\n) async throws -\u003e R where C: Clock, R: Sendable { ... }\n\npublic func deadline\u003cR\u003e(\n  until instant: ContinuousClock.Instant,\n  tolerance: ContinuousClock.Instant.Duration? = nil,\n  isolation: isolated (any Actor)? = #isolation,\n  operation: @Sendable () async throws -\u003e R\n) async throws -\u003e R where R: Sendable { ... }\n```\n\nThis function provides a mechanism for enforcing timeouts on asynchronous operations that lack native deadline support. It creates a `TaskGroup` with two concurrent tasks: the provided operation and a sleep task.\n\n- Parameters:\n  - `instant`: The absolute deadline for the operation to complete.\n  - `tolerance`: The allowed tolerance for the deadline.\n  - `clock`: The clock used for timing the operation.\n  - `isolation`: The isolation passed on to the task group.\n  - `operation`: The asynchronous operation to be executed.\n\n- Returns: The result of the operation if it completes before the deadline.\n- Throws: `DeadlineExceededError`, if the operation fails to complete before the deadline and errors thrown by the operation or clock.\n\n\u003e [!CAUTION]\n\u003e The operation closure must support cooperative cancellation. Otherwise, the deadline will not be respected.\n\n### Examples\nTo fully understand this, let's illustrate the 3 outcomes of this function:\n\n#### Outcome 1\nThe operation finishes in time:\n```swift\nlet result = try await deadline(until: .now + .seconds(5)) {\n  // Simulate long running task\n  try await Task.sleep(for: .seconds(1))\n  return \"success\"\n}\n```\nAs you'd expect, result will be \"success\". The same applies when your operation fails in time:\n```swift\nlet result = try await deadline(until: .now + .seconds(5)) {\n  // Simulate long running task\n  try await Task.sleep(for: .seconds(1))\n  throw CustomError()\n}\n```\nThis will throw `CustomError`.\n\n#### Outcome 2\nThe operation does not finish in time:\n```swift\nlet result = try await deadline(until: .now + .seconds(1)) {\n  // Simulate even longer running task\n  try await Task.sleep(for: .seconds(5))\n  return \"success\"\n}\n```\nThis will throw `DeadlineExceededError` because the operation will not finish in time.\n\n#### Outcome 3\nThe parent task was cancelled:\n```swift\nlet task = Task {\n  do {\n    try await deadline(until: .now + .seconds(5)) {\n      try await URLSession.shared.data(from: url)\n    }\n  } catch {\n    print(error)\n  }\n}\n\ntask.cancel()\n```\nThe print is guaranteed to print `URLError(.cancelled)`.\n\n## Improvements\n- Only have one free function with a default expression of `ContinuousClock` for the `clock` parameter.\n  - Blocked by: https://github.com/swiftlang/swift/issues/72199\n- Use `@isolated(any)` for synchronous task enqueueing support.\n  - Blocked by: https://github.com/swiftlang/swift/issues/76604\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fph1ps%2Fswift-concurrency-deadline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fph1ps%2Fswift-concurrency-deadline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fph1ps%2Fswift-concurrency-deadline/lists"}