Is Span Sendable? #2346
-
Hi! I would like to propagate Spans in my app using TaskLocal, but I get a warning that Span is not Sendable so I am not sure if this is safe to do. public enum Logging {
@TaskLocal static var span: Span? = nil
}
// ... someplace else in the app
func task1() async {
let transaction = SentrySDK.startTransaction(name: "Task1", operation: "Task1")
await Logging.$span.withValue(transaction) {
await task2()
}
}
func task2() async {
let span = Logging.span?.startChild(operation: "Task2")
//...
span?.finish()
} Maybe this could also be achieved with |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments
-
Hi. No, span is not sendable. Your assumption about solving this with |
Beta Was this translation helpful? Give feedback.
-
I see, but how would // Task 1
Task.detached {
// some random thread, let's call it thread 1
let transaction1 = SentrySDK.startTransaction(name: "Transaction 1", operation: "Op 1", bindToScope: true)
await work1()
transaction1.finish()
}
// Task 2
Task.detached {
// some random thread, let's call it thread 2
let transaction2 = SentrySDK.startTransaction(name: "Transaction 2", operation: "Op 2", bindToScope: true)
await work2()
transaction2.finish()
}
func work1() async {
// some random thread, not guaranteed to be the same as the caller, so maybe a thread 3
SentrySDK.span // is this transaction 1 or transaction 2?
}
func work2() async {
// some random thread, not guaranteed to be the same as the caller, so maybe a thread 4
SentrySDK.span // is this transaction 1 or transaction 2?
}
// possible execution order
// Task 1 (binds transaction 1 to scope) -> Task 2 (binds transaction 2 to scope) -> work2 -> work1 My concern is that a child span might get the wrong parent. let parentTransaction = SentrySDK.startTransaction(name: "Transaction 1", operation: "Op 1")
let parentId = parentTransaction.context.spanId
// ... somewhere else
SentrySDK.startTransaction(transactionContext: .init(trace: .init(), spanId: .init(), parentId: parentId, operation: "Child span", sampled: .undecided)) |
Beta Was this translation helpful? Give feedback.
-
Ok, I got it. Your concern is legit, the child will most definitely end up in the wrong transaction. bindToScope overrides any previous value "binded" before. Right now we don't offer a built in solution for this scenario, you will need to handle transaction references yourself between tasks. |
Beta Was this translation helpful? Give feedback.
-
Hi @StefanCosminR , I'm going to close this discussion as resolved for now as it hasn't been updated in a while. If you still need assistance or were unable to get a solution working for yourself, don't hesitate to reopen or to open an issue down the line 🙏🏻 |
Beta Was this translation helpful? Give feedback.
Ok, I got it. Your concern is legit, the child will most definitely end up in the wrong transaction. bindToScope overrides any previous value "binded" before.
Right now we don't offer a built in solution for this scenario, you will need to handle transaction references yourself between tasks.
A Sendable wrapper to hold the transaction reference is probably the easiest solution right now.