[New feature] Version 9: Update Thing actions that did not change a thing don't store updated fields in 'Results of step ...' thing

Hi all,

we’re going to be rolling out a consistency change which, while minor, has the potential of breaking some implementations of workflows.

This can best be described with an example:

Say you have a workflow with two steps:

  • Step 1: Make changes to a Thing, where the Thing to update is a search for that Thing. You are updating Field A to ‘Hey!’
  • Step 2: Display data in a Text Group that contains the Result of Step 1’s Field A.

If the search for things returns an actual thing in your database to update, then everything works as it did previously: “Result of Step 1” did and will still contain the thing which you created or updated, which therefore have all its fields, including the updated Field A, and therefore Step 2 will set Group data to text ‘Hey!’

If the search for things returned nothing, you will not be updating anything: Step 1 is basically a no-op.
The results of Step 1 do not contain an actual thing in your database, so all its fields should be empty.

This is where the breaking change happens:

New behavior:
In particular Field A will henceforth be also empty, because nothing was updated, and there are no results to step 1. Step 2 will set Group data to no text, because “Result of Step 1’s Field A” is empty.

Old behavior:
Result of Step 1 would contain an extremely barebones ghost Thing, with no id nor any field, EXCEPT for the changed fields, which were inferred to have successfully been updated. Result of Step 1’s Field A would therefore be ‘Hey!’ and the Group Data in Step 2 would be set to text ‘Hey!’.

If you recognize this behavior in your app, and rely on the updated fields even when nothing did change, here’s the suggested change in order to adapt to this update:
Just make sure that instead of using “Result of Step X’s updated field”, write down the equivalent definition you set when changing the property on the ‘Make changes to a thing’ action earlier.

Note: this also applies to “Make changes to a list of things” in the same way.

11 Likes

Thanks for the info, @aless! Quick question…

And so the Result of step 1 will itself also be empty, as was the case previously?

I often use Make changes to a thing to actually “fetch a thing” with no intention of making changes to it, but I do check if the thing itself is empty (an object was actually retrieved).

Thanks for the clarification.

-Steve

6 Likes

This is a great improvement and will go a long way in helping us develop more stable applications with predictable behaviour.

Good Job,

I also make changes to a think to get it specifically to use the result of step feature, I dont get if you asked a question and if it was answered. Can someone please let me know if that will continue to work? I’m sorry but this update is hard for me to understand.

2 Likes

Yeah, might need some clarification, I read this a few times and don’t understand what exactly changed.

4 Likes

@aless has yet to respond, so my question is unanswered.

1 Like

As I understand it, the old behavior would give the false impression that the field(s) of a nonexistent thing had been updated if you checked the fields in a subsequent step (when they of course could not have been if there was no actual thing retrieved). By contrast, the new behavior returns “empty” for any fields that you attempted to update on the nonexistent thing.

My question was simply whether “empty” would still be returned for the nonexistent thing itself. (I suspect the answer is yes.)

-Steve

2 Likes

Hey @aless,

What was the reason for this update? What does it improve? Can you give an example where old behaviour caused issues to demonstrate the improvement?

I often use “Result of step …” for convenient access to the value I search for only once and then refer to it in the following steps to change other things using its field values. Does it mean that after this update I’ll have to search for the same thing every time I need to read its values? How much does it impact performance? Isn’t it more efficient to search for the same thing only once and refer to it later?

Also are you sure with old behaviour it returned a “ghost thing”? I just made a quick test similar to one in your post, on step 1 it searches for a thing and changes nothing, then on step 2 it makes changes to “Result of step 1” and it worked, the thing was changed. Doesn’t look like a ghost.

What’s going on here?

2 Likes

Please answer this one.

And so the Result of step 1 will itself also be empty, as was the case previously?

I often use Make changes to a thing to actually “fetch a thing” with no intention of making changes to it, but I do check if the thing itself is empty (an object was actually retrieved).

Thanks for the clarification.

-Steve

Hi @sudsy, I do want to confirm that your use-case is not affected by this, as that already exhibits the ‘expected’ behavior of fetching the updated thing, and being empty if nothing was updated.

@andrey_li, I can provide an example of how this is a predictability improvement, in the sense that it clarifies the edge case of a step where you updated a thing, but that step did not find anything to update and therefore its ‘result’ was empty.

To be completely clear, you can totally keep on using the results of this step as a way to access the updated item - like you’re saying quite well, that’s still definitely the preferred way to access Things on subsequent steps of a workflow.

Maybe my semantics were unclear actually:

  • If you make changes to a Thing that exists, but change no field, results of that step always have and still contain that Thing.
  • If you make changes to nothing (a Thing that does not exist) and change one or more fields, the results of that step used to be “mostly nothing” but with ghost updated fields, and will now be “definitely nothing”.

As for the ‘ghost’ behavior I alluded to, that is the following:
setup (using the setup from my example):

  • You have a Thing table with no entries at all, and Thing has a Field A of type text.
  • You have a ‘Make changes to a thing’ action, that does a search for the first item in the empty Thing table (or any search that does not return a thing)
  • This search sets Field A to ‘hey’

In following steps, let’s look at some expressions for Result of Step 1:
Result of Step 1 is empty -> yes
Result of Step 1’s unique id -> (empty)
Result of Step 1’s unique id is empty -> yes
Result of Step 1’s Created Date -> (empty)
… this would also be the case for fields not mentioned in the previous case (everything would be empty)

now before version 9,
Result of Step 1’s Field A -> ‘Hey’
Result of Step 1’s Field A is empty -> no

After version 9,
Result of Step 1’s Field A -> (empty)
Result of Step 1’s Field A is empty -> yes

This is a lot more consistent with what actually was changed, because in essence we don’t want to have any partial Thing exist in limbo during your workflow run like this: the resulting Thing would essentially be something without a unique id, no fields whatsoever, except for a few fields that would have inherited the values from previous steps, which is why I refer to it as a ghost thing. It would also not match anything in the database, so it is safer to make sure that it does not contain any fields.

I hope this clarifies the updated behavior for everyone!
Cheers,

5 Likes

Thanks a lot, this clarifies the update!

It was confusing because I never assume a Thing is not empty and always check, so I didn’t realize there was a use case where you’d end up with a ghost Thing.

2 Likes

FYI, one use case for rely on the “old” way is to handle race conditions: when there may be multiple parallel API’s trying to write to the same row, and you need to reference the API values that may have not “won” the race condition. The update behavior will not supply these ephemeral values within the “Step X” methodology.

The recommended workaround will not solve this, so those that rely on this behavior will need to create a separate (supertype) table that can act as a temp value container of all parallel API’s that may be racing for the original target update. The API’s write to both the target and the supertype along with a token (random text), you can then anti-join/filter to figure out the values that were not written, using a Step X’s token = Search For Supertype’s Token methodology within each workflow if necessary.

1 Like

This version change actually eliminates all usage and solving of race conditions and leaves us with absolutely no way to handle race conditions in workflows… It’s a bad update the previous way it was done is the correct and reasonable one! Always return the “Thing” !