-
Notifications
You must be signed in to change notification settings - Fork 148
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
[#1962] Add newCallbackExecutor to interceptors and override for OpenTracing #2366
base: master
Are you sure you want to change the base?
Conversation
Hrmm, this is a very specific interceptor-oriented solution to a general problem of contextual state across promises. I wonder if a |
@cretz, if I understand what you are saying, I think we'd still need to use interception at some level unless OTEL can be made to utilize the WorkflowAsyncLocal instead of ThreadLocal because something would need to initialize the state in the callback context, which currently runs outside of the RootThread complex. I'm not saying OTEL can't use WorkflowAsyncLocal; I just don't know |
for (Functions.Proc handler : handlers) { | ||
handler.apply(); | ||
} | ||
executor.execute(() -> handlers.forEach(Functions.Proc::apply)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this change is not backward compatible and can break determinism.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mfateev are you referring to the forEach or the executor deferment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should add: Executor makes no assumptions about async/sync execution models...I chose it because it seemed to have the right abstraction where the context creation is decoupled from the execution of the Runnable. However, I fully expect any interceptor only to use synchronous execution to avoid changing the model. I could make this more explicit or use a different abstraction if we think the use of Executor confusingly suggests async or promotes abuse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added documentation to clarify the synchronous requirement and changed to a plain for() loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that switching from direct call to an executor that might change the order of execution of these calls can lead to non determinism. Such changes should be protected by versioning/patching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. FWIW: I was careful to design the executor chain in a way that should respect the original order of interceptors, and I retained the original order of the for loop as well. I suspect your concern would be if someone added an interceptor that creates an NDE situation, but I think that if that were the case, they should follow patching procedures in the intercept code. I don't think we could solve that at this level. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mfateev I looked, and I don't see any apparent examples of SDK code using patching internally. Since I don't believe the PR code changes the ordering, the only NDE potential that I see would be if an interceptor introduced a determinism issue in its handler. However, that would also concern any existing interception points, so it's unclear if this proposed one should be treated differently.
This is a blocking issue for me, so I am highly motivated to see it get merged. So please let me know what you'd like to see done here, and I will do my best to make it happen.
temporal-opentracing/src/test/java/io/temporal/opentracing/CallbackContextTest.java
Show resolved
Hide resolved
.../main/java/io/temporal/opentracing/internal/OpenTracingWorkflowOutboundCallsInterceptor.java
Outdated
Show resolved
Hide resolved
a572f48
to
e714fc3
Compare
…e for OpenTracing This change adds newCallbackExecutor to the OutboundInterceptor interface, overriding the OpenTracing behavior. This allows the OpenTracing interceptor to transfer any active trace/span from the point of creation to the point of deferred execution, thus preserving the span within the callback. Without this, spans become disjoint across Promise.thenCompose, due to the nature of the deferring the execution of the .thenCompose to a callback thread. Fixes temporalio#1962 Signed-off-by: Greg Haskins <[email protected]>
This change adds newCallbackExecutor to the OutboundInterceptor interface, overriding the OpenTracing behavior. This allows the OpenTracing interceptor to transfer any active trace/span from the point of creation to the point of deferred execution, thus preserving the span within the callback.
Without this, spans become disjoint across Promise.thenCompose, due to the nature of the deferring the execution of the .thenCompose to a callback thread.
Fixes #1962
Checklist
Closes Tracing context does not propagate into .thenCompose #1962
How was this tested:
A unit test was developed first to confirm the issue. The solution was iterated over until the unit test passed satisfactorily. The unit-test is included in the MR for inclusion with the code-base
Any docs updates needed?
No.