What are the orchestrating cases not suitable for Temporal?

Hey friends, I wanna start this topic for some discussions in case we set no boundaries and apply Temporal everywhere.

Currently, I find Temporal may not be a good choice for the processes with these features:

(1) transient and no need to make the process durable and retry at all

e.g. some reactional read-only API that combines all the data of TikTok and returns these data to an end-user. Of course, temporal can handle this but seems not very necessary.

(2) very in-time APIs which tolerate very short response time. (not sure about this one, very happy to hear a different voice)

because it seems Temporal is event-driven and there may be a gap of time between sending out the start workflow request and waiting for the re-transmits between different workers, and the finish of the execution. The tasks in the queue may pile up and the response time of the activity seems hard to monitor.

(1) transient and no need to make the process durable and retry at all

If these are just “fire and forget” type operations and you do not care about resilience, then using Temporal might indeed be overkill for your use case.

(2) very in-time APIs which tolerate very short response time. (not sure about this one, very happy to hear a different voice)

If you are referring to realtime use cases such as gaming and streaming where you need super low latencies then yes. Temporal does optimize its transactional consistencies tho to be as low as possible.

yeah, wanna explain more on (2) user makes some purchase on amazon commodity and wait for the pay’s return info, do you still suggest Temporal can handle this with the sync.Get() on awaitable. I just feel afraid the waiting time can be long?

I think for any systems dealing with critical operations such as purchases/money transfers Temporal bring huge value. The fact that your mission critical operations can execute to completion despite failures such as infrastructure outages etc outweighs possibly small latency differences you might be able to squeeze out of non-fault-tolerant stateless solutions.

I just feel afraid the waiting time can be long?

Could you elaborate more on this? With Temporal you can start workflow execs async and wait for their results async as well.

I came up with another case for this topic. I have the pseudo-code here. The starter of this workflow should get the fail error for the “lock” in a sync way, and tell the user immediately that his request should fail. But if it doesn’t fail, the caller does not need to wait for the remaining part to finish in a sync way.

Could Temporal handle this or should we just make the locking part out of the workflow?

func Workflow (ctx) error {
  // short and quick, should fail immediately and not retry
   err := workflow.ExecuteActivity(tryDistributedLock)
if err != nil {
   return err
}
  // long
   err := workflow.ExecuteActivity(makeAGlobalTransaction)
if err != nil {
   return err
}
return nil
}

Could Temporal handle this or should we just make the locking part out of the workflow?

I would in workflow code start a child workflow async (see here on how to do that). This child workflow is going to execute the two activities. If first activity fails it would then signal the parent workflow and parent workflow on receiving this signal can just just return (with custom message if you need). That way you can respond back to your caller as soon as activity 1 fails, and have the child workflow continue execution.

What is the scope of the lock? Frequently you can use a workflow uniqueness for a specific ID as a lock replacement.

for example, in the common sync code style: we need to lock the account when one transaction happens, and if the user makes another one after the distributed lock in Redis fails and we tell the user it’s not allowed. I haven’t figured out how to make this happen, not quite understand homer’s solution, seems we can make the first activity with lock sync, wait on this, and let the rest of the activities in the workflow async. But, I don’t think it is a good pattern, not sure what will happen to the workflow status, will it run to completion with the inner async activities unfinished?

not sure if the following design is what is proposed?

func Workflow() {
   err := execute.Activity(lock on the redis).Get()
  if err: return err
// 
   execute.Activity(xxx)
}

You can use workflow as a lock. See the mutex sample.

yeah, I see we can have the async child-workflow do the rest of the work, and wait on the lock-child-workflow. I suppose the child-workflow doing the lock job can also be one activity, and the parent workflow just waits on the result of it. Am I making any sense here?

Yeah, thanks. I have a look here. This makes me a little confused.

  1. Other none temporal locks possibly here
    I see the signals between a mutex workflow so that the one receiving the mutex workflow reply gets the lock. What confuses me here is do we need to do so in temporal workflow, since it is not that easy.
    Can we just use Redis for some mutex for coordination and just wrap this in Redis, will there be a problem with that?

  2. About the ORDER:
    I think mutex here cannot guarantee the order of 2 requests? since there are many workers out there to start to execute a workflow, it is possible for a client to issue the request very fast twice and they are handled by different workers, and the second request gets the lock first.

1 Like

About the order, it seems to me even if you implement a Redis distributed lock, you will encounter the same issue. Since the problem is that the client issued two requests almost the same time and the requests should be processed in order but they are processed concurrently.

for redis with sync child workflow/activity and async child, I think the second call just gets an error.

func Workflow() err {
       var has_lock bool
       activity(lock).get(ctx, &has_lock)
       if not has_lock {
              return err
       }
      async childworkflow      
}


func someCaller() {
       err = startWorkflow().Get() //sync blocking here for return
}

Can the two requests be processed by 2 different replicas of the server application, and the second request happens to acquire the lock before the first request?

yeah, I think without temporal and we use grpc, the 2 requests can also go to different servers? (I am not quite sure our current grpc logics) It seems by using sync-wait on the caller of workflow, it works the same way our current grpc system does.

Can we just use Redis for some mutex for coordination and just wrap this in Redis, will there be a problem with that?

Is Redis distributed lock fully durable? Can it last for a few weeks, for example? Having just one runtime dependency usually has better availability and easier to troubleshoot.

  1. About the ORDER:
    I think mutex here cannot guarantee the order of 2 requests? since there are many workers out there to start to execute a workflow, it is possible for a client to issue the request very fast twice and they are handled by different workers, and the second request gets the lock first.

This is incorrect. Temporal guarantees uniqueness of workflow executions by their ID. Note that this uniqueness is ensured by the Temporal service and is not related to the number of workers an application uses. So any requests to the same workflow instance will be serialized and processed one by one. You can see them in the same order in the workflow execution history, for example.

About order, I mean

the user, by sequence, starts 2 workflow executions (with 2 ids), the 2 are competing for the lock. can we guarantee the first workflow execution gets the lock first? I am not confident here.

I don’t understand the problem you are trying to solve. Two independent workflow executions competing for the lock cannot guarantee the order in which they are going to ask for the lock. The locking workflow implementation can have any type of business logic. For example, do not give a lock for the second workflow if the first one wasn’t granted yet.