Workflow method thread handling when using the Temporal Java SDK

Hi, I have a few questions related to how threads are handled in code being run in an application using the Temporal Java SDK.

  1. When a workflow method calls an activity synchronously does the application continue to hold a thread running the workflow method until the activity returns and the workflow method execution can continue?
  2. Based on other community posts it seems that calling await or sleep in a workflow method suspends the thread running the workflow method. Does this mean the suspended thread’s context is stored locally in the application’s memory?
  3. Will any incoming task for an awaiting/sleeping workflow method signal the suspended thread leading it to be woken up, even if the incoming task has nothing to do with the await condition or the sleep timer?
  4. Related to threads and await/sleep, is it still correct that await/sleep are the best way to delay a workflow’s start?
  1. Yes, Sync invocation is a blocking operation and would block the currently executing workflow thread until activity completes.
    One thing to mention here is that workers have a workflow execution cache (in memory). In case of long blocking operations the worker can evict it from cache and the used threads can be freed up. This is powerful because in case you have millions of concurrently running workflow executions that are waiting for activity completions they do not all have to occupy threads.

  2. Temporals workflow threading model allows only one thread to be executed at a time Workflow.sleep, Workflow.await, Promise.get etc would block the current thread and allow another workflow thread to execute.
    Workers cache workflow executions (in memory), see worker tuning guide for more info on worker cache configuration.
    If a workflow execution is in memory, it’s just a normal Java thread. If its evicted from worker cache these threads are freed up.

  3. For await, the unblock condition is evaluated on each state transition, so it would unblock the thread if its evaluated to true based on the current workflow state and condition.
    For sleep, the durable timer is created on the server and sdk would need to look at the workflow task information to know when to unblock.

  4. Yes it is if you need that to be done as part of your business logic (workflow code). Another way is to delay starting workflow execution on your client side.

Thanks for reply!
Some further clarifying questions:

  1. Yes, Sync invocation is a blocking operation and would block the currently executing workflow thread until activity completes.
    One thing to mention here is that workers have a workflow execution cache (in memory). In case of long blocking operations the worker can evict it from cache and the used threads can be freed up. This is powerful because in case you have millions of concurrently running workflow executions that are waiting for activity completions they do not all have to occupy threads.

If a long blocking executing workflow thread is evicted from the workflow execution cache does that mean that that workflow’s execution state will eventually be entirely reconstructed solely from the event history? Does this mean that state of any local variables like progress in a for loop would be lost? What about local variables that were updated by incoming signals? Because incoming signals are recorded in event history would the local variables be updated to have the correct value once the entire workflow execution state is reconstructed?

  1. Temporals workflow threading model allows only one thread to be executed at a time Workflow.sleep, Workflow.await, Promise.get etc would block the current thread and allow another workflow thread to execute.
    Workers cache workflow executions (in memory), see worker tuning guide for more info on worker cache configuration.
    If a workflow execution is in memory, it’s just a normal Java thread. If its evicted from worker cache these threads are freed up.

Does this mean that only one workflow execution can be making progress at a time on a worker?

  1. For await, the unblock condition is evaluated on each state transition, so it would unblock the thread if its evaluated to true based on the current workflow state and condition.
    For sleep, the durable timer is created on the server and sdk would need to look at the workflow task information to know when to unblock.

Does this mean that when using await and having it wait purely on a condition a server side durable timer and corresponding event in the event history (TimerStarted/TimerFired) is not created but await with both a timer and a condition and sleep do create a server side durable timer? If the workflow execution waiting purely on an await with just a condition is evicted from the worker cache would any incoming task for that workflow need to rebuild the workflow execution from the event history to evaluate if the await condition is met?

If a long blocking executing workflow thread is evicted from the workflow execution cache does that mean that that workflow’s execution state will eventually be entirely reconstructed solely from the event history?

Yes, worker would have to replay its history from the beginning, and then proceed execution.

Does this mean that state of any local variables like progress in a for loop would be lost?

Workflow state would be reconstructed during history replay.

What about local variables that were updated by incoming signals?

Signals are recorded in workflow history. During replay your signal methods would be re-executed and put the state back to where it was.

Does this mean that only one workflow execution can be making progress at a time on a worker?

No, it’s per execution.

Does this mean that when using await and having it wait purely on a condition a server side durable timer and corresponding event in the event history

For sleep, it wakes up based on the the trigger (durable timer firing, recorded in history)

For await it depends on the await as there are two options,

await(unblockCondition)
await(timeout, unblockCondition)

For await(unblockCondition) the unblock condition is re-evaluated on “triggers for a potential advancement” such as incoming signals, custom timers firing, etc. There is no server-side created timer.

For await(timeout, unblockCondition) there is also a server side durable timer that can trigger as well.

If the workflow execution waiting purely on an await with just a condition is evicted from the worker cache would any incoming task for that workflow need to rebuild the workflow execution from the event history to evaluate if the await condition is met?

If the workflow execution is not in cache workflow history replay would happen regardless of the last executed workflow code, before its put back in cache.

Got it. Thank you @tihomir