-
Hi team, I came across the Orchestrator function code constraints doc and see the following statement: Orchestrator code must never start any async operation except by using the IDurableOrchestrationContext API, the context.df API in JavaScript, or the context API in Python. For example, you can't use Task.Run, Task.Delay, and HttpClient.SendAsync in .NET or setTimeout and setInterval in JavaScript. The Durable Task Framework runs orchestrator code on a single thread. It can't interact with any other threads that might be called by other async APIs. I wonder would awaiting an async method (not I/O bound) count against such constraint? We are using AsyncLocal to act as a context provider for our instrumentation, and in order to do that, we need to wrap the actual async operation invoked through the IDurableOrchestrationContext API within another async delegate, something like this:
In such case, do you think it would cause any problem? If so, is there any other way to achieve a similar thing (providing a context accessor per function execution scope while not relying on DI)? |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments
-
@dxynnez in the code you shared, it doesn't look like you're actually starting any async operations. You're just wrapping normal Durable operations in an async method, which is perfectly fine. Really, the thing that we need to protect against is introducing new threads into the orchestration's execution. The Durable Task Framework must control the single thread of execution in order to ensure determinism. APIs like Task.Delay and HttpClient.SendAsync typically have callbacks execute on worker pool threads, which is what causes problems. That's not happening in your case. |
Beta Was this translation helpful? Give feedback.
-
Thanks so much @cgillum . That's what I figured. I am relatively new to the .NET async world, could you elaborate a bit more on what counts against the said 'async operation'? Is it only for the APIs under the System.Threading.Tasks namespace plus some other APIs that would spin up a new thread (I know it's probably irrelevant to durable function but it would be great if you can guide me to some docs)? Thanks again! |
Beta Was this translation helpful? Give feedback.
-
No problem @dxynnez! One way I like to think about it don't await a task if you don't know where it's coming from. If it comes from a method on This idea of "trusted" or "safe" tasks is pretty unique to Durable Functions so I don't think there is a lot of useful documentation in the general .NET async that goes into this. There is some generic documentation which might be helpful as context. |
Beta Was this translation helpful? Give feedback.
-
Thanks @cgillum . That helps! |
Beta Was this translation helpful? Give feedback.
@dxynnez in the code you shared, it doesn't look like you're actually starting any async operations. You're just wrapping normal Durable operations in an async method, which is perfectly fine. Really, the thing that we need to protect against is introducing new threads into the orchestration's execution. The Durable Task Framework must control the single thread of execution in order to ensure determinism. APIs like Task.Delay and HttpClient.SendAsync typically have callbacks execute on worker pool threads, which is what causes problems. That's not happening in your case.