According to the documentation the steps in workflows do not run synchronous but rather parallel. And it is also written that there are
Workarounds to help achieve workflow consistency:
Or in other words, forget about workflow consistency altogether.
Let’s try the above example and see if and how it would ever be possible to store some simple information with relations in a consistent, repeatable way into the database, using workarounds.
It’s a simple process, that creates a person and assigns one or many roles in a movie. (Actor, Writer, Director). The Role being one entity between Movie and Person with one or more entries in the Role property, since one person can have many roles in the same movie.
- Step 1 creates the person, but only if it doesn’t exist already.
- Step 2 relies on Step 1, in order to create workflow consistency. But if step 1 doesn’t create a person, because it already exists, Step 2 fails to assign the person to the role, because there will be no result from Step 1.
- Step 3 fails if there is no role entity in the database, which in this case is highly probable, because Step 2 and Step 3 are run parallel, and Step 3 might not find the Role from Step 2.
“Workarounds” and their impossibilities:
- Let Step 2 search for the Person in the database instead. This will fail, when Step 1 indeed creates a new person. Again because of parallel execution.
- Let Step 3 be reliable on Step 2’s result. This will fail in an iteration where Step 2 does not create a new role, because a Role entity already exists.
- The option “add a pause before next action” from the documentation is not available in backend workflows
No matter how I try to look at this, I have no idea how to fix this.
Seems to be another candidate for outsourcing to Backendless…
There is nothing wrong with Bubble. You are missing some important details…
Why don’t you create another step in your workflow to create a role to the person if this person already exist in your database? As I see you are creating a role ONLY WHEN your search for the selected person is empty (because you need the result of first step).
You need to replicate your second step to create a role ONLY WHEN your search for the selected person is not empy (the same “only when” search you are using in your firs step, but instead of use “is empty”, use “is not empty”).
And in the field “A_01_Person” or this step you can write something like this:
A_01_Person = Search for A_01_Person :first item
Don’t forget you also have the option of terminating a workflow.
+1 to @rpetribu 's solution.
What you need to fix is to do the search first to verify whether the user exists, before creating a new user. This ensures that you don’t create duplicate users. Also, not sure whether you are aware, but conditions can be set on workflow events as well(not just the steps).
Thank you @rpetribu, your input was really helpful and set me on the right track.
I found the solution by contemplating again on the options I have with Bubble and by adding a truth table.
There are 3 entities in the in the database whereas Role connects Movie and Person. Combining all the possibilities of either existing or non-existing object in relation to the other two results in 8 possible combinations, (2 to the power of 3) whereas case 3, 4 and 7 are invalid cases/combinations and should never exist. The workflow gets executed recursive, so I don’t know in what order or what state the database is in at the time of execution.
The truth table shows what cases I actually have to focus on, and what can be ignored. For this workflow, case 1-4 is irrelevant, because the movie must exist before it’s even possible to enter the workflow, which is triggered by clicking on a movie.
The hard part was to arrange the steps around case 5, 6 and 8 and to workaround Bubbles way of executing everything at once.
- Step 1 covers case 5, when there is no person yet
- Step 2 covers also case 5 and triggers therefore only when there is a new person. It adds the role to the person when there was no person before. (Actor, Writer, Director)
- Step 3 covers case 6 when there is already a person but no role. Therefore Step one is empty and therefore the condition must be different then in Step 2. It adds a role to the person, when a person already exists.
- Step 4 covers case 8. It adds another role to the person for the same movie.
And here is one more important point: Step 3 and 4 can not be interchanged, because Step 4 must be sure, that Step 3 has not created a role. Because if it did it must be case 6. If the steps were interchanged it could easily happen again that, due to parallel execution, changes were made to a role that should not be made. These are the nuances that pops up easily in sneaky ways, when everything gets thrown at you executed parallel.
The nice thing about truth tables though is that it makes testing so much easier. You can just work your way through each case and if the result is equal the desired outcome you can be fairly sure that the system works properly. You could even stress test your system through the non valid cases, just to make sure, that nothing breaks if requests are coming in, you thought would never come in to begin with.
Hi @CosmicSelf ,
if you want to make sure that workflow steps wait for each other you can use custom events. This warrants workflow consistency. If you use custom events within the longer workflow script - all steps after particular custom event will wait before execution for that custom event to finish.
Thanks for the input @Guru, unfortunately the results of custom events can not be use further in the workflow Are triggers in backend workflows executed asynchronous? - #4 by CosmicSelf
No probs. Well it all depends on the case but you could use custom events togheter with custom states. This will enable you to have the result “outside” of a custom event thus use it however you want both on client and server side. It’s not the cleanest way (im aware) but it does the job.
Interesting approach. But how do you use custom states on the backend workflow? I don’t see any option for that.
Well it’s quite simple → You use custom state value with schedule workflow and set that value there and that’s basically all.
Because you know that custom event need to finish before the rest of the code is fired you set the custom state in that custom event and next you schedule workflow with that custom state value.
Ofc my printscreen is super simple - normally you would need to add a value for that workflow but I assume that you perfectly know how to push values from client to server.
Something that might help - maybe you’re onto this, maybe you’re not - is that when you configure your backend calls using the API connector (rather than
Scheduling an API workflow) you get to take advantage of async features at the point of call (be it on the front or backend) and subsequent steps that reference
Step x's response will wait for that response to be received. That response can contain any data that you like.
It takes a bit more setup but it’s worth it IMO to get around some of the race conditions issues you’re seeing.
This topic was automatically closed after 70 days. New replies are no longer allowed.