Queries regarding lifetime of Job passed to executor

Hi All. I have gone through the Job documentations:

The consuming variant of Job is only available from iOS 17+, for earlier versions the Job being passed to executor is of type UnownedJob. Does the lifetime of this type follow the same lifetime as the consuming equivalent? i.e. the Job is alive till it is executed once? Is it safe to save the job of this type and differ the execution after certain asynchronous condition is satisfied, i.e network call completed?

  • job enqueued
  • save job
  • perform network call
  • network call completed
  • execute saved job
1 Like

Here is the sample executor implementation for my use-case:

final class CustomBarrierExecutor: SerialExecutor, Sendable {
    @TaskLocal static var ignoreBarrier = false

    private nonisolated(unsafe) var jobs: [UnownedJob] = []
    private nonisolated(unsafe) var executingBarrier = false
    let queue: DispatchSerialQueue

    init(queue: DispatchSerialQueue) {
        self.queue = queue
    }

    func asUnownedSerialExecutor() -> UnownedSerialExecutor {
        return UnownedSerialExecutor(ordinary: self)
    }

    func enqueue(_ job: UnownedJob) {
        let ignoreBarrier = Self.ignoreBarrier
        queue.async {
            if !ignoreBarrier && (self.executingBarrier || !self.jobs.isEmpty) {
                self.jobs.append(job)
                return
            }

            job.runSynchronously(on: self.asUnownedSerialExecutor())
        }
    }

    func executeBarrier(action: () async -> Void) async {
        dispatchPrecondition(condition: .onQueue(queue))
        self.executingBarrier = true
        await action()
        queue.async {
            self.executingBarrier = false
            while !self.jobs.isEmpty {
                if self.executingBarrier { break }

                let job = self.jobs.removeFirst()
                job.runSynchronously(on: self.asUnownedSerialExecutor())
            }
        }
    }
}

Is this executor safe to use?

The UnownedJob has the same semantics as ExecutorJob, just that it is unsafe in the sense that the type system does not help you with the “run it just once”. If you run it twice you’ll cause undefined behavior (bad bad things).

See docs: UnownedJob | Apple Developer Documentation

1 Like