Interrupts
As per the Concepts Docs, you can set up a ThreadSpec such that when an ExternalEvent of a certain type comes in, the ThreadRun is interrupted and an Interrupt Handler ThreadRun is spawned.
To do so, you can use WorkflowThread#handleInterrupt(). There are two required arguments:
- The name of the
ExternalEventDef. - A lambda function, interface, or
ThreadFuncdefining the handler thread (generally, this is a lambda function).
Note that when a ThreadRun is Interrupted, it must first halt. A ThreadRun is not considered HALTED until all of its Children are HALTED as well. Therefore, interrupting a ThreadRun causes all of the Children of the Interrupted ThreadRun to halt as well.
Example
In this example, we have a WfSpec that defines a long-running WfRun that uses an email address (stored as a WfRunVariable) to communicate with a customer.
What if the customer changes their contact info? Let's define an ExternalEventDef named email-update whose content is a STR value with the new email address. We will use that ExternalEventDef and an Interrupt to update the Variable used to contact the customer.
Variable Scoping
Recall that the interrupt handler is a Child ThreadRun of the Interrupted ThreadRun, which means that it has read and write access to the Interrupted thread's Variables.
Accessing the Event Content
ExternalEvents have a payload. When you create your Handler ThreadSpec, you can access that content by creating a WfRunVariable with the name "INPUT". For example, if the payload of your ExternalEvent will be a JSON_OBJ, you would do:
- Java
- Go
- Python
- C#
thread.declareJsonObj(WorkflowThread.HANDLER_INPUT_VAR);
thread.DeclareJsonObj("INPUT")
thread.declare_json_obj("INPUT")
thread.DeclareJsonObj(WorkflowThread.HandlerInputVar);
Putting it Together
Here's a complete example:
- Java
- Go
- Python
- C#
public void threadFunction(WorkflowThread thread) {
// The Variable used to keep track of email in the parent thread.
WfRunVariable email = thread.addVariable("customer-email", VariableType.STR);
// Register the Interrupt Handler
thread.registerInterruptHandler(
"email-update",
handler -> {
// Store the content of the event
WfRunVariable eventContent = handler.addVariable(
WorkflowThread.HANDLER_INPUT_VAR,
VariableType.STR
);
// Mutate the variable
handler.mutate(email, VariableMutationType.ASSIGN, eventContent);
}
);
// Omitted: your long-running business logic that uses the `customer-email` variable
}
func threadFunction(thread *littlehorse.WorkflowThread) {
// The Variable used to keep track of email in the parent thread.
email := thread.AddVariable("customer-email", lhproto.VariableType_STR)
// Register the Interrupt Handler
thread.HandleInterrupt(
"email-update",
func (handler *littlehorse.WorkflowThread) {
// Store the content of the event
eventContent := handler.AddVariable(
"INPUT", // the special name to get interrupt trigger
lhproto.VariableType_STR,
)
// Mutate the variable
handler.Mutate(email, lhproto.VariableMutationType_ASSIGN, eventContent)
},
)
// Omitted: your long-running business logic that uses the `customer-email` variable
}
def my_interrupt_handler(handler: WorkflowThread) -> None:
# Get variable from parent thread
email = handler.find_variable("customer-email")
# Store the content of the event
event_content = handler.add_variable("INPUT", VariableType.STR)
# Mutate the variable
handler.mutate(email, VariableMutationType.ASSIGN, event_content)
def my_entrypoint(wf: WorkflowThread) -> None:
# The Variable used to keep track of email in the parent thread.
thread.add_variable("customer-email", VariableType.STR)
# Register the Interrupt Handler
wf.add_interrupt_handler("email-update", my_interrupt_handler)
public static void ThreadFunction(WorkflowThread thread)
{
// The Variable used to keep track of email in the parent thread.
WfRunVariable email = thread.DeclareStr("customer-email");
// Register the Interrupt Handler
thread.RegisterInterruptHandler(
"email-update",
handler =>
{
// Store the content of the event
WfRunVariable eventContent = handler.DeclareStr(WorkflowThread.HandlerInputVar);
// Mutate the variable
handler.Mutate(email, VariableMutationType.Assign, eventContent);
}
);
thread.SleepSeconds(120);
// Omitted: your long-running business logic that uses the `customer-email` variable
}
How to trigger an Interrupt event
Please refer to: Posting External Events.
Notes and Best Practices
First, only one ThreadSpec may register an Interrupt Handler for a given ExternalEventDef.
Additionally, note (as per the Concept Docs) that the Interrupt Handler Thread is a Child of the Interrupted ThreadRun. This is a very useful feature, as it means that the Interrupt Handler may modify the variables of the interrupted thread.
If you use an ExternalEventDef as a trigger for an Interrupt, you cannot reuse that ExternalEventDef for a wait for ExternalEvent node.