api-swift / Sources / IrdAPI / Core / Polling.swift
238 words
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import Foundation

/// Backoff for poll loops: `interval` doubles up to `maxInterval` between attempts
/// until `timeout` has elapsed. The first attempt always runs, even with a zero or
/// negative timeout.
public struct PollOptions: Sendable {
    public var interval: Duration = .seconds(1)
    public var maxInterval: Duration = .seconds(8)
    public var timeout: Duration = .seconds(120)
    public var message: String = "Timed out polling"

    public init(interval: Duration = .seconds(1), maxInterval: Duration = .seconds(8),
                timeout: Duration = .seconds(120), message: String = "Timed out polling") {
        self.interval = interval
        self.maxInterval = maxInterval
        self.timeout = timeout
        self.message = message
    }

    public static let jobs = PollOptions(message: "Timed out waiting for the job")
    public static let uploads = PollOptions(timeout: .seconds(300), message: "Timed out waiting for the upload")
    public static let actions = PollOptions(message: "Timed out waiting for the action")
}

/// Runs `step` until `done`, sleeping with doubling backoff between attempts; throws
/// `IrdError.timeout` carrying the last result once the deadline has passed.
public func pollUntil<T: Encodable & Sendable>(
    _ options: PollOptions, clock: any IrdClock,
    step: @Sendable () async throws -> T, done: @Sendable (T) -> Bool
) async throws -> T {
    let deadline = clock.now + options.timeout
    var interval = options.interval
    while true {
        let result = try await step()
        if done(result) { return result }
        if clock.now >= deadline {
            throw IrdError.timeout(message: options.message, last: try? JSONValue(encoding: result))
        }
        try await clock.sleep(for: interval)
        interval = min(options.maxInterval, interval * 2)
    }
}

static mirror of HEAD · about · clone: git clone https://ird.cod-sursa.ro/api-swift.git