-
Notifications
You must be signed in to change notification settings - Fork 101
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
Side effects / Workers / LifecycleWorker methods not called if rendered/not rendered without ever yielding dispatch #1093
Comments
Am I overthinking and we should provide a Workflow node related lifecycle hook for this and leave the job out of it? not sure. |
In the test, w/o yield, do any of the |
Seems like we have a bigger problem than this ticket implies: |
Add headlessIntegrationTest to renderWorkflowIn with a nice Turbine attached. Closes #1093
Add headlessIntegrationTest to renderWorkflowIn with a nice Turbine attached. Closes #1093
Add headlessIntegrationTest to renderWorkflowIn with a nice Turbine attached. Increase perf benchmarks render pass expectations as yield() will do that. Closes #1093
Add headlessIntegrationTest to renderWorkflowIn with a nice Turbine attached. Increase perf benchmarks render pass expectations as yield() will do that. Closes #1093
For the record: we just chatted, and we think that using We believe that |
Solves #1093 Add headlessIntegrationTest to use for the new test case
Solves #1093 Add headlessIntegrationTest to use for the new test case
I'm no longer thinking this is the case. When using So when we use To get around that we would have to use a lock at the start of every side effect until render is complete. While this would mean that some coroutine for a side effect was always started, it wouldn't matter as the I'm more convinced now that we should let the coroutines behavior - of respecting cancellation before dispatch - win out here and impact how side effects are run. We can add a new API for this use case though - a non-suspending lambda for when the side effect is complete that we will attach to the e.g. somehting like:
|
I actually can't yet figure out how to make a test that will reproduce the nested EventLoop scenario that causes the out of order dispatch (where we use an unfrozen render context). The scenario in the PerformancePoetryActivity does reproduce this, but I can't isolate what about it does that in a unit test. So perhaps the scenario where the lock prevents the side effect from being run is less frequent than we thought? |
interesting - the lock does not check for cancellation if it doesn't suspend - see documentation here:
So this is actually perfect for us. As the side effect will continue to run (atomically) until its first real suspension point, if render has completed before dispatch occurs. Only in the mysterious cases where it hasn't completed and the lock is locked when we try to acquire it, then it will suspend. So i'm back to thinking this actually may be a good solution. |
So that will work for almost all cases. The nested cases when using an Unconfined or immediate dispatcher will likely result in suspending on the lock waiting for render complete, so in those cases the side effect won't be fired after cancel(). I should be clearer about what is working - here is a snippet:
I have a hunch that our internal use case is likely the nested scenario. Have not confirmed yet. We could force the sideEffect to happen each time with NonCancellable but that's not what we want because then it would never get cancelled. e.g., THIS WON'T WORK:
So, to cover all use cases I'm thinking about adding a param to the We'd use it like:
OR
This should cover all of our use cases as well as do the best effort to honor starting the actual sideEffect() block (if it was ever declared running) in as many cases as possible. It does beg the question though if we add an optional My answer to that right now would be that using an |
since worker is built on
runningSideEffect
, the easier way to reproduce this is:If this is rendered and not rendered within the same thread frame (e.g. using the Main.Immediate dispatcher and cycling back and forth),
error()
will never get called.At the very least this needs to be updated in the documentation.
This is because the Job's for side effects are started using
CoroutineStart.LAZY
so that we don't end up sending anything to theactionSink
until after therender()
method is complete and theRenderContext
frozen (then we callstart()
on all the side effect jobs - see here.What would be better if we provided a hook to the side effect's Job's
invokeOnCompletion
which will be invoked even if cancelled before the coroutine gets dispatched. E.g. see this test:Which prints "I'm complete" but not what is in the finally block (without the
yield()
).I propose this could be called.
RenderContext.onNoLongerRendered()
. It has to be outside ofrunningSideEffect
's lambda because that won't ever get invoked. We want to attach this right on theJob
we create for the side effect.The text was updated successfully, but these errors were encountered: