mirror of
https://github.com/corda/corda.git
synced 2024-12-19 04:57:58 +00:00
297e504740
* CORDA-3291 `isKilled` flag and session errors for killed flows ## Summary Two major improvements have been worked on: - A new flag named `isKilled` has been added to `FlowLogic` to allow developers to break out of loops without suspension points. - Killed flows now send session errors to their counter parties allowing their flows to also terminate without further coordination. Achieving these changes required a __fundamental__ change to how flows are killed as well as how they sleep. ## `isKilled` flag The addition of `FlowLogic.isKilled` allows flows to check if the current flow has been killed. They can then throw an exception to lead to the flow's termination (following the standard error pathway). They can also perform some extra logic or not throw an exception if they really wanted to. No matter what, once the flag is set, the flow will terminate. Due to timing, a killed flow might successfully process its next suspension event, but it will then process a killed transition and terminate. ## Send session errors when killing a flow A flow will now send session errors to all of its counter parties. They are transferred as `UnexpectedFlowEndException`s. This allows initiated flows to handle these errors as they see fit, although they should probably just terminate. ## How flows are killed ### Before Originally we were relying on Quasar to interrupt a flow's fiber, we could then handle the resulting `InterruptedException`. The problem with this solution is that it only worked when a flow was already suspended or when a flow moved into suspension. Flows stuck in loops did not work. ### After We now *do not* use Quasar to interrupt a flow's fiber. Instead, we switch `FlowStateMachine.isKilled` to true and schedule a new event. Any event that is processed after switching this flag will now cause a `KilledFlowTransition`. This transition follows similar logic to how error propagation works. Note, the extra event allows a suspended flow to be killed without waiting for the event that it was _really_ waiting for. This allows a lot of the tidy up code in `StateMachineManager.killFlow` to be removed as tidy up is executed as part of removing a flow. Deleting a flow's checkpoint and releasing related soft locks is still handled manually in case of infinite loops but also triggered as part of the actions executed in a transition. This required flow sleeping to be changed as we no longer rely on quasar. ## How flows now sleep The reliance on Quasar to make a flow sleep has been removed. Instead, when a flow sleeps we create a `ScheduledFuture` that is delayed for the requested sleep duration. When the future executes it schedules a `WakeUpFromSleep` event that wakes up the flow... Duh. `FlowSleepScheduler` handles the future logic. It also uses the same scheduled thread pool that timed flows uses. A future field was added to `StateMachineState`. This removes the need for concurrency control around flow sleeps as the code path does not need to touch any concurrent data structures. To achieve this: - `StateMachineState.future` added as a `var` - When the `ScheduledFuture` is created to wake up the flow the passed in `StateMachineState` has its `future` value changed - When resumed `future` and `isWaitingForFuture` are set to `null` and `false` respectively - When cancelling a sleeping flow, the `future` is cancelled and nulled out. `isWaitingForFuture` is not changed since the flow is ending anyway so really the value of the field is not important. |
||
---|---|---|
.. | ||
src | ||
build.gradle |