Forum Academy Marketplace Showcase Pricing Features

Force Workflow Steps to Happen in Order

Hi,

TL;DR: How can one ensure that the workflow steps happen strictly in order?

I have a workflow where I would like to validate that a thing doesn’t already exist in the database before creating it. However, the thing is being created before the validation is done, resulting in the validation counting the thing as having been in the database even though it was just created. This is happening despite the creation of the thing being listed as a step that comes after the validation. Adding pauses doesn’t work as pauses don’t affect changes to the database. I switched it from creating the thing in the same workflow to one where a new workflow is triggered where the thing is created at the end of the first workflow, but to no avail. The steps are not occurring in sequential order. The thing is being created before its time, and its creation is tripping the validation (via custom states) resulting in false errors being created. This can be seen very clearly in debug mode, where the creation of the thing happens before it is supposed to. When it’s live, it’s inconsistent, as if at times it validates faster than the database is edited, and at other times, it validates slower.

TL;DR: How can one ensure that the workflow steps happen strictly in order?

Workflow steps are designed to occur one after the other, however, they will not necessarily complete before the next steps is triggered.

Think about it like firing a gun that you pull the trigger and the bullet leaves the barrel…maybe the first gun (the first step) is triggered first and its target is 2 miles away and as soon as you pull that trigger you then pull the trigger of a second gun (the second step gets triggered) and that target is 200 meters away…the bullet from the second gun will hit its target before the first bullet has hit its target.

You have a lot of terminate this workflow and a lot of conditionals that are impossible to see or understand how they might be affecting your outcome…it is best to run through step by step mode in the debugger to try and figure out what is going on.

Another thing that you may do is create a conditional workflow that will trigger the booking with the conditional being met when the earlier steps are complete.

Thanks,

The terminates and conditionals are my attempts to ensure that it doesn’t get to step 10 before completing step 3.

If there’s an error in the booking, I want it to stop.


image

If there’s an existing booking, I want it to show an alert, then stop,



image

Only when there’s no error, and no existing booking, do I want it to create one.
image

Unlike your suggestion, there’s no “only when step x is complete” option.

As stated, when in debug mode, it is crystal clear that the booking is triggered before the checks are complete, leading the check to claim there’s an existing booking when the booking that exists is the one that was created ahead of its time. I know that this is happening because if I remove the trigger booking from the workflow, it doesn’t trigger the booking. I spent hours and hours figuring out the issue to see what is going on, I’m now looking for a solution for it.

The gun analogy doesn’t explain a solution as much as it does provide a metaphor for the problem. Pull the trigger again only once the first shot has missed its mark. The result of the first shot influences whether or not I take the second, so I don’t want to fire my gun a second time unless the first shot misses. Think sniper, not Rambo.

Beyond neatness, it’s a deeply functional problem. It means a) bookings are created even when there’s an error because the booking creation is happening before the error check executes. b) The alert that there is an existing booking is shown even though there wasn’t an existing booking because the intended (booking that was created before its time) is being caught up in the check for an existing booking. c) If there was an error, the time slot cannot be used again because a booking has been created in it which was invalid or did not complete because the workflow terminated, and the false booking cannot be automatically deleted because there’s no programmatic way to distinguish between false and true bookings.

Now I see what you are trying to do…previously working with that one screen shot didn’t give too much to go on, or what your interpretation of a booking validation would entail.

How are you providing the user with the ability to select a date or time to make a booking? If it is just a simple calendar and they are free to choose any day or time they wish with no restrictions, that might be where the real problem is.

When making a booking app it is better to restrict the users ability to select a date and time based on the availability, rather than what you are attempting with the multiple conditionals, checks, triggers etc.

Think about it like this: if you put a conditional onto a calendar element to restrict the dates visible, the user would not be able to select a date that already has an existing booking for that date, so you would no longer need all the checks and validations you are attempting.

Instead you would enable a user to only see when a booking slot is available and they can choose from the available slots.

Also, think about it from a UX perspective. How frustrating would it be as a user to see something you want to book, choose a date or time to book it, and then be told “oh sorry, that is not available”…instead the user should see from the beginning only the dates or times that are available.

You might also want to try using Custom Events for your set state actions.

When a custom event is triggered in a workflow, the workflow is paused until the custom event has run to completion, and then resumes.

Thanks for your response, and for thinking through it deeply.
Yes, it’s a simple calendar where one can choose any day or time. This is in addition rather than instead of restricted pre-set availabilities that have been created by a user. This is being done for the very same UX purposes you’ve mentioned, to increase the flexibility for bookers and to lower the cost of using the service for listing creators. With a purely “choose from my available slots” repeating group, the convenience given to the bookers adds work for the listers, who have to create multiple availabilities. If they don’t, the assumption is that they are busy, and so bookings are not created. The truth is more that they are lazy rather than genuinely unavailable, and do not want to have to create availabilities every single time. This makes them less likely to use the app, and if they don’t create availabilities, it means bookers won’t be able to reach them, so they don’t use the app. The ultimate result is a dead app.

It’s also more flexible for the bookers. They’ve seen what’s available, so they look amongst those first. Don’t see a time that suits you? Make a request for a booking. Not providing this option is a sure way to kill conversion, because more likely than not, a lister is able to accommodate a request outside the listed availablities, and not just because of the laziness described above, but because they’re human. So the “cost” of picking a time outside the listed availabilities only to be told that that specific requested time is definitely already taken is very low compared to being given no alternative and therefore leaving the app (most likely) or using the messaging system to request an ‘off calendar availability’ session (if you’re extremely determined).

Not offering flexibility therefore doesn’t just hurt the booker user experience, it hurts and complicates the listers user experience, makes it harder for the booker and lister to connect, and ultimately, hurts the platform.

To use another metaphor, when doing a pre-flight check, you can’t start taxiing on the runway just because you had begun the check for fuel first, but began to take off before the fuel check had finished. The fact that passengers must wait a bit longer for the pre-flight checks to all conclude before the flight occurs does not so terribly destroy the user experience so as to make them not fly. But taking off and then being told that the fuel check ostensibly started before the take off is now complete with the plane in the air, and there’s not enough fuel, would destroy the user experience, even if the initial take off happened a bit faster.

When I have this issue on long workflows I break it up into states/workflows

Try using a custom state on your parent group called like “api success” it is a Boolean Default no

Break the original workflow down and when action is complete set state to yes

Then have a workflow for “when a conditional is true” -> when parent group “api success” is yes
-> (2nd part of original workflow)

Make sure you empty the state and have the conditional workflow set to every time rather than one time.

You can do this multiple times if needed.

I thought that this was brilliant and destined to work and celebrated.
image
Unfortunately, it did not. The next trigger was called before the first was done. I haven’t yet figured out why.

You should do what @chris.williamson1996 mentioned…it is the same as below but with more direction provided

Set step 2 to use result of step 1 in one of it’s value fields. Seems to be a pretty reliable way of enforcing sequential execution.

Customs don’t work because the custom triggers and instantly starts the flow regardless of others being done with a full response from external sources.

Using states like I mentioned above works the same way API response events work by not triggering until a api response isn’t empty.

Thanks for this @chris.williamson1996,

Really interesting suggestion and I’ve reworked the workflows to make it function as you’ve laid out in addition to incorporating @adamhholmes suggestion . However, after much testing, it still doesn’t reliably work to my utter confusion. It seems to work at normal speed, but not at step-by-step speed, which really confuses me and makes debugging of other issues rather impossible.

TL;DR: Slow Mode and Step-By-Step mode seem to have a bug at the Bubble level that normal mode does not that makes step-by-step or slow debugging nearly impossible.

The high level workflow is now broken into three major (error prone) sub-stages:

In the first, I have triggered the pre booking checks, and added before & after states, as per your guidance.

image

image

Once the final “Ready for Booking” Error state is changed to a yes, and only when it is yes, should the next stage, the booking, begin:
image
image

Despite two levels of checking whether the condition has been met, the booking somehow still happens. I’ve isolated it to the booking and not the error states, because removal of the booking stage from the workflows doesn’t result in a booking.

On the debug step by step mode, it claims to work exactly as you said it would: the booking workflow does not get triggered. However, the reality is that it does get triggered even though it shows as not triggering in debug step by step mode. Weirdly, in the normal mode, it functions (so far) as intended.

I make a booking:

image

The top level workflow is triggered:

And before it gets to the trigger booking, it’s already made the booking:

This seems to be an issue with the step-by-step mode of debug. With the normal mode, the issue seems resolved by following what you @chris.williamson1996 and @adamhholmes said in combination. The bubble loading bar still chugs on even in debug step-by-step mode.

To test this, I made shapes appear within each workflow and disappear within the next workflow, so that if the workflow was entered, I’d know, and I’d see if the same actions responded differently in normal mode vs. step-by-step mode.

image
image
image

Different shapes appeared depending on the mode chosen. In normal mode, the shape that was supposed to appear in the first trigger and disappear in the second trigger (shape jemima) never appeared at all. The shape meant to appear in the second trigger and disappear in the third trigger did just that (shape williamson). The shape meant to appear in the third trigger and disappear at the end of the workflow (shape adam) never appeared at all.

Slow mode and step-by-step mode result in a different sequence (and thus different boxes). In Slow mode, the first box in the first trigger (shape jemima) appears. Slow mode / step-by-step mode invariably results in an error being created, and thus the condition for triggering the other steps not being initiated, the other shapes for trigger 2 (shape williamson) and trigger 3 (shape adams) are never called, and shape jemima is never hidden.

TL;DR: Slow Mode and Step-By-Step mode seem to have a bug at the Bubble level that normal mode does not that makes step-by-step or slow debugging nearly impossible.

Try running this without custom events.

Rather click the add a new workflow for under your workflow tab

“when condition used true”

This will trigger the event upon state being true run the workflow then reset state. Rather than you triggering a custom in the prior flow.

What this does is say hey do action 1 from the original workflow add a wait 1-5s then set state of the parent group to true.

Upon the state being it will then and only then trigger the workflow.

If you do with customs it does a check for yes no instantly rather than waiting for a finish on the first flow.

Hope that makes sense.

1 Like

Hi @chris.williamson1996,

I followed what you said. It works, but step-by-step mode now crashes bubble.

Yeah we run into this all the time. Huge race condition. This is because workflows do NOT execute sequentially across all actions as one would think. It actually executes them based on action type in three different sequential buckets, in parallel. The actions are split up as:

-API calls
-DB actions (make changes/create new thing/etc)
-Everything else / State changes / Visual actions (hiding/animating/display data/etc)

The engine appears to pre-scan your workflow, schedule API calls it can first, make DB changes second, and then call anything else last. We solve this via two primary methods:

calling an action with conditional “Result of stepX is not empty” on a DB action will ensure the DB is evaluated prior to the conditional action ensuing

SCHEDULING (not triggering) a custom event will ensure it happens apart from the race condition (hence place your latter conditional action in a custom workflow then schedule it with a 1 second delay) EDIT: also add a terminate workflow conditional on the start of your scheduled workflow to abort if your undesired fail-state occurs regarding your booking)

1 Like

Thnaks @jesse.r.hunter ! In my case I’m trying to send an email to admin after the user registers an offer but the …conditional “Result of stepX is not empty”… makes the send email step to fail. Any workaround on this besides schuduling custom events?

{Result of StepX is not empty} is only actually empty for:
-Inserts that fail to actually isnert due to a constraint violation or something similar
-Updates that don’t actually update anything (the search returns no rows on what to update)
-All deletes (which I hate, returning rows affected would’ve been sweet)

If you are creating/registering a DB object, that’s an insert, and shouldn’t actually return empty. Mind sharingg your workflow via screenshot? What could also be a solution is on the email step, set the Do When conditional to be Result of StepX:count > 0