-
Notifications
You must be signed in to change notification settings - Fork 266
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
Context propagation? #194
Comments
@stephenh Since parseq tasks are not guaranteed to run in one thread, thread-local cannot work in parseq setting. Your understanding about using decorated executor service to capture the state of "psuedo thread locals" when callables/runnables are submitted to the underlying executor is completely correct, that is the typical way to propagate execution context from task to task. But I don't quite understand your phrase below: "which makes sense for the initial engine.run call, but I can't reason about whether then the entire rest of the task/plan will similarly have the "captured on engine.run" state passed along at each async task invocation." Can you elaborate that a bit? As for Task.blocking(..., executor), to propagate execution context to such blocking task, you also need to pass the same decorated executor service in this call. |
@mchen07 Do you think it's better to propagate context using |
Hi @mchen07 ; thanks for your response!
Sure. The context being captured when the first task is submitted to the executor makes sense. What I don't know is that, after that initial task has fired and caused N other tasks to happen, when those children tasks complete, and are put into the executor to be executed, how will the captured state follow them along? In theory if the child tasks were created immediately in the 1st executor execution, they would get picked up, e.g.:
However, it seems like tasks are not submitted to the executor immediately while evaluating the 1st task, which of course makes sense because their async, so I think see this happen: https://github.com/stephenh/java-sandbox/blob/parseq/src/main/java/sandbox/Foo.java Which I think is:
Is there an easy way, within the Basically I want an Invocation Context. |
@angxu That is a good suggestion, I am considering that for plan-local cache (#193). That needs some code change in SerialExecutor, as well as some thoughtful API designs for task writer to update/access the plan-local context. With current parseq support, it seems that implementing customized ExecutorService and wrapping each callable submitted to it may be one potential way to propagate context within or even across plans. |
@stephenh Basically to carry over context from task to task during plan execution, you need to create a decorated executor service on top of JDK provided ExecutorService. The Executor is decorated to maintain ExecutionContext that you can define yourself: when a Runnable is submitted to the Executor, the ExecutionContext of a submitting thread is captured and stored together with a Runnable; when Runnable is about to be executed, stored ExecutionContext is restored on a current thread (mostly a thread-local storage) and Runnable is executed. |
@mchen07 yeah, that makes sense...if the |
@stephenh I may need to look at "PropagatingExecutorService" class implementation to see how it is propagating context through tasks. Normally it should involve code to decorate the submitted Runnable to save and restore context. |
Hi; this is not an issue, but a question; sorry, I couldn't find/didn't see a better forum to ask.
Does Parseq have an API/mechanism for passing context along within a task?
I know/assume this machinery exists within Parseq itself for doing tracking/execution, but I'd basically like ThreadLocal-style hooks to put user-/application-defined state in (like our own request/trace ids, or other app context), and, from looking at the API/examples, I don't see an obvious way of doing this.
I know Parseq runs on executors, so I thought of using something like this, which captures the state of "psuedo thread locals" when callables/runnables are submitted to the underlying executor, which makes sense for the initial
engine.run
call, but I can't reason about whether then the entire rest of the task/plan will similarly have the "captured onengine.run
" state passed along at each async task invocation.I guess for
Task.blocking(..., executor)
, if that executor was also instrumented to trigger the context recording, theexecutor.execute
would record the context, and when the callable runs and callspromise.done
, the context would have been "put back", and so as long aspromise.done
led to a synchronous enqueue into the parseq executor (which would again trigger a context record), it'd get picked up/passed along.So, I think that makes sense? for
Task.blocking
going to other executors, but I haven't thought through/figured out how the async, just regulartask.andThen(...)
would work.If you could provide any help/pointers/docs/APIs/etc., I'd appreciate it!
Or if it's as easy as using the java-thread-context approach, and as long as all of my application's executors are sufficiently instrumented, it will just magically work, that would also be great, and I'm just making this harder than it is.
The text was updated successfully, but these errors were encountered: