Wait_condition on signal execution model

Hi,

If I have a workflow like the SDK example, that has a signal and uses wait_condition

@workflow.defn
class ClusterManagerWorkflow:
    def __init__(self) -> None:
        self.state = ClusterManagerState()

    @workflow.signal
    async def start_cluster(self) -> None:
        self.state.cluster_started = True

    @workflow.run
    async def run(self, input: ClusterManagerInput) -> ClusterManagerResult:
        self.init(input)
        await workflow.wait_condition(lambda: self.state.cluster_started)

Can you help me understand the execution model?

In between the workflow starting and the signal being sent (let’s say it’s days later), is this workflow going to execute hundreds of times and each time exit early when the lambda evaluates to false?

Or is Temporal aware that it will only evaluate to true after a signal is sent, so it won’t advance until a signal gets recorded?

I’m trying to build my mental model since it seems like I should be able to indicate that “hey don’t worry about this one at all until the signal gets sent”, but it’s not clear to me how that would happen in practice in that example. It seems like it would need to track all the ways that self.state could be modified, and know that receiving a signal is the only way, and then record that somewhere.

Is it that involved? or is it the much simpler “try to run it, and see what happens with the lambda”? And if it’s that simple, is there a way to get the behavior I’m talking about of “don’t worry about this thing again until the signal (in general “some external action”) comes through.”?

What I’m really trying to do is not have a worker tied up checking the lambda super frequently when I know it doesn’t need to, and it feels like I’m not using these features properly.

We wouldn’t provide such a function if it had bad runtime behavior. wait_condition is only evaluated when the workflow state changes. So it will not be evaluated while the workflow waits for a signal.

That’s great to hear, and thanks for the super quick reply.

Can you help me understand how that works? I’m still not fully understanding how it accomplishes that and I’d like to have a better mental model for using wait_condition so I can use it confidently.

As an example, if I had a lambda that was checking workflow.time() > $some_value, would it also know not to re-run again until that statement would be true? Or would it need to run repeatedly?

No, time cannot be used in the condition as the condition is only evaluated when the workflow state changes. That’s why the condition accepts the timeout as an argument.

Ah okay, I think I get it now.

So when I call wait_condition, it essentially puts the workflow to “sleep”, so it won’t be re-executed until something changes the workflow state from the “outside” (e.g. a signal).

My mistake was thinking that because I didn’t specify what signal to wait for, that temporal would have to continually re-evaluate the condition function in order to know whether to proceed, but it’s simpler than that. It just won’t re-evaluate it until something triggers the workflow to run again (e.g. the timeout or a signal).

So there is nothing stopping me from putting something like workflow.time() in the lambda (like it won’t throw an Exception), but it won’t “work” in the sense that it won’t get re-evaluated until either the timeout or some signal wakes the workflow up.

To be clear, I don’t have any reason to put workflow.time() in there, and realize that doesn’t make sense to do, I’m just using that as an example of something that would change continuously to help me understand.

Thanks!

I think you underestimate your insight. It is absolutely not obvious that waiting doesn’t work for time-based conditions.