Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task Local Value Binding crash when used legally using withTaskGroup #73217

Open
Joannis opened this issue Apr 24, 2024 · 0 comments
Open

Task Local Value Binding crash when used legally using withTaskGroup #73217

Joannis opened this issue Apr 24, 2024 · 0 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. concurrency Feature: umbrella label for concurrency language features crash Bug: A crash, i.e., an abnormal termination of software

Comments

@Joannis
Copy link

Joannis commented Apr 24, 2024

Description

A number of users of MongoKitten use the driver with task groups. I've long recommended using MongoKitten's database cursors as an async sequence to iterate results. However, often times, developers want to iterate a sequence to spawn work using a task group.

try awaitwithThrowingTaskGroup(of: EmailResult.self) { taskGroup in
  for try await subscriber in mongodb[NewsletterSubscriber.self].find() {
    taskGroup.addTask {
      try await emailClient.sendEmail(to: subscriber.emailAddress)
    }
  }
}

From my perspective at least, no illegal task local binding happens. But since MongoKitten's find() function uses swift-distributed-tracing, the compiler spawns an assertionFailure.

Reproduction

enum Tracing {
    @TaskLocal static var callingFunction: String?
}

func makeIntegers(callsite: String = #function) async -> [Int] {
    Tracing.$callingFunction.withValue(callsite) {
        return [0, 1, 2]
    }
}

await withTaskGroup(of: Void.self) { taskGroup in
    for i in await makeIntegers() {
        taskGroup.addTask {
            print(i)
        }
    }
}

Stack dump

error: task-local: detected illegal task-local value binding at __lldb_expr_3/TLV.playground:6.
Task-local values must only be set in a structured-context, such as: around any (synchronous or asynchronous function invocation), around an 'async let' declaration, or around a 'with(Throwing)TaskGroup(...){ ... }' invocation. Notably, binding a task-local value is illegal *within the body* of a withTaskGroup invocation.

The following example is illegal:

    await withTaskGroup(...) { group in 
        await <task-local>.withValue(1234) {
            group.addTask { ... }
        }
    }

And should be replaced by, either: setting the value for the entire group:

    // bind task-local for all tasks spawned within the group
    await <task-local>.withValue(1234) {
        await withTaskGroup(...) { group in
            group.addTask { ... }
        }
    }

or, inside the specific task-group child task:

    // bind-task-local for only specific child-task
    await withTaskGroup(...) { group in
        group.addTask {
            await <task-local>.withValue(1234) {
                ... 
            }
        }

        group.addTask { ... }
    }
Playground execution failed:

error: execution stopped with unexpected state.
error: Execution was interrupted.
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.

Expected behavior

The task local binding works in this instance.

Environment

Xcode 15.3's bundled Swift toolchain

Additional information

No response

@Joannis Joannis added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Apr 24, 2024
@hborla hborla added concurrency Feature: umbrella label for concurrency language features and removed triage needed This issue needs more specific labels labels Apr 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. concurrency Feature: umbrella label for concurrency language features crash Bug: A crash, i.e., an abnormal termination of software
Projects
None yet
Development

No branches or pull requests

2 participants