async let vs Task.detached when work must escape actor isolation but keep tracing context
21.5K reputation · 15 Apr 2022, 20:23 UTC
I have a Swift service where a method on an actor needs to kick off a background export. The work should not hold the actor's lock while it runs, but it does rely on a task-local tracing ID and should still stop if the caller's task is cancelled. I am weighing two documented options: a structured child task via async let, or an unstructured Task.detached.
My understanding is that async let inherits the enclosing actor isolation, priority, and task-local values, and is cancelled with the parent, while Task.detached drops all of that context and runs independently. That seems to put my two requirements in tension: escaping actor isolation appears to require detaching, but detaching appears to forfeit the task-local propagation and cancellation I depend on. A plain Task {} is a third option, but as an unstructured task its lifetime would need manual management.
Assume Swift 5.9 or later with strict concurrency checking enabled.
Is there a documented way to escape the actor's isolation for the heavy work while still inheriting task-local values and priority, or must I pick one side of this trade-off?
If I choose Task.detached and explicitly pass the tracing ID in as an argument, do I also lose cooperative cancellation from the original caller, or only automatic cancellation propagation?
Does the answer change depending on whether the export genuinely needs to outlive the calling scope versus merely needing to run off the actor?