Promise.all() in JS/TS workflow

Hi,

Is it correct to say, that I can use Promise.all() in JS/TS to branch multiple activities inside the workflow and wait for them to sync back?

Thanks

Yes, you can use any of the Promise static methods, not just all depending on the desired behavior.

Generally you can treat the workflow runtime as you would any other JS runtime. We only prevent usage of a couple APIs: WeakRef and FinalizationRegistry because those have observable non-deterministic behavior.

1 Like

Awesome, thank you for confirmation and extra bits!

Looks like I’m able to translate any business workflow with timers and branching into a single async function definition (Workflow Definition). Which is impressive.

Will go and learn more :slight_smile:

Is it possible to get nondeterminism errors when using Promise.all with activities when a workflow stops and restarts and the activities execute in a different order? (Because I think this is happening to me now)

I realize this thread is old, but its the only one I’ve found on the topic.

What do you mean by “stops and restarts”? Workflows don’t restart on worker crashes. They recover and continue from the point of the worker’s crash.

My understanding is that when the worker comes back up it re-runs the workflow code and essentially returns the stored results from the the activities until it gets to the part of the workflow that didn’t execute yet. There is also the reset workflow to specific event concept.

I’m getting this error: “[TMPRL1100] Nondeterminism error: Activity type of recorded marker ‘activityOne’ does not match activity type of local activity command ‘activityTwo’” when no code has changed. (“[TMPRL1100] Nondeterminism error: Activity id of scheduled event ‘8’ does not match activity id of activity command ‘9’” for non-local activities")

I believe this is due to the Promise.all I’m using, but I am looking for verification of that theory.

Promise.all() is expected to be ok. The error you are describing looks very much like a bug in the SDK.

And actually, I think I have an idea what the bug is. To confirm, would it be possible for you to share some snippet of what you are doing in your workflow code? I really don’t need a full repro at this point, just an overview of how activities are being called while inside the Promise.all block.

I am also seeing a bunch of TMPRL1100 errors when using Promise.all. I have a workflow processing a custom DSL (graph based) and calling a bunch of activities, often in loops. Here is a small code sample from my loop handler:

const batch = slicedArray.slice(batchStart, batchStart + batchSize);

await Promise.all(batch.map(async (item, batchIndex) => {
  const index = batchStart + batchIndex;

  // Process iteration path
  await Promise.all(iterationPaths.map(async (iterationPath) => {

    // processStep will call the next step that's most likely an activity
    await processStep(iterationPath.targetId, merge({}, context, {
      loop: {
        [step.id]: {
          item,
          index,
          iterationId: `${step.id}-${index}`,
        },
      },
    }));
  }));
}));

Do I understand correctly that merge and processStep are both Local Activities?

merge is just the merge function from lodash. processStep is a workflow function: takes a step data (which can be an action, loop, conditional etc) and runs it, then it calls the next step recursively. The code snippet is from the loop handler.
Almost all handlers call local activities at some point.