Temporal Signal + Query Sequence Guarantee

Hey,

I Hope @maxim can help with this question, apologies for the personal AT here, but this question perplexes us for a while and is on the critical path and really matters to us with our first project with temporal in our company.

The context here is

  1. the workflow execution waits on signal A to proceed
  2. several users can send the A with their userID attached to it;
  3. our signal handler now takes the first user as accepted
private val waitingSignals = mutableListOf<SignalApproverActionDto>()

override fun submitApprovalAction(dto: SignalApproverActionDto) {
    waitingSignals.add(dto)
}

override fun queryUserTaskAcceptedApproverId(taskId: String): String? {
    if (executionContext.currentTaskId != null && executionContext.currentTaskId.toString() == taskId) {
        if (executionContext.currentApproverId == null && waitingSignals.size > 0) {
            return waitingSignals[0].userTaskId
        }
    }
    return null
}

  1. but since there is no reply from the Signal we cannot get the result if the user is taken by the signal as the first one
  2. our design is when the user from the web endpoint sends out the signal, our web service queries it from workflow execution to check the contexts of the list to find who is the first

The question here is
our API logic is signal+query, can we assume that the temporal SDK/workers guarantee that when we guarantee the sequence of signal, then query; the workers also follow the sequence: finish the signal logic first, and then respond to our query, so we always have some data in the list

Hi @maki_XIE

Temporal guarantees read after write consistency of signal and then query.

If your signal method is blocking might happened that the query runs before the signal returns. Looking at your code, it does not seem to be the case.

Here are some references:

I hope this helps,

I am pretty sure that Maxim can provide a more detailed explanation here (or correct me if I am wrong).

2 Likes

Hey, thanks for the reply. really helps, I have a little follow-up question is about “signal method is blocking”. So if I put heavy logic , for example query from a slow DB, the query runs before signal because the “coroutine” inside temporal code blocks on signal and handles query instead. Am I understanding this correctly or some other worker picks up the query so I get a wrong result?

We need to estimate a little what are the cases and possibility we don’t get it.

@antonio.perez

So if I put heavy logic , for example query from a slow DB, the query runs before signal because the “coroutine” inside temporal code blocks on signal and handles query instead.

Your query methods should “query/return” workflow state, it should not do db read/writes. These types of operations should be done via activities.

or some other worker picks up the query so I get a wrong result

Each received signal is handled in its own workflow thread. In the signal-then-query scenario the signal handler is invoked before the query is handled. However if your signal method blocks (on Workflow.sleep for example) the received query can be handled when the workflow task completes which can happen before signal handler completes.

1 Like