How do I stop the iterator module mid-iteration?

How do I break out of a Flow Control Iterator’s iterations?

Context: provisioning new members with email handles in our Google workspace domain. We use various combinations of the letters in a first and last name along with middle name initial if we have it. Prior to the scenario, I generate a bunch of possible combinations - enough to guarantee that we’ll be able to make unique handles for our member population as it grows (& any member may have their account in our domain for up to a decade.)

So, the scenario receives this array of possible values, splits them into bundles, and evaluates each bundle’s value to see if it is already in use. When the search module finds one not already in use (or suspended), a new account is created with that handle as the primary email address. at this point in the scenario, I’d like the iterator to stop iterating over any remaining bundles.

Once a match is found and I make a new user, I no longer need to continue with the iterating. If possible, I would just as soon not use the tasks it will take to process the remaining bundles.

FWIW, I have filters set up between modules and use a data store to handle identifying the state change from “Handle not in use && New Handle not yet created” to “Handle not in use && Handle already created.” This way, if the first item gets used for the new handle, I won’t create user accounts for the following iterations, but for each one, I will use a task for the filter check.

Is it possible to make the iteration (and effectively the scenario) stop after the new user account is created?

As best I can tell, however many items you feed the iterator, it will process all of the bundles.

As a more concrete example, let’s say I have an array of [a, b, c, d, e] which I turn into bundles.

I iterate over the bundles one item at a time with the downstream branch from the iterator module.

Let’s say the first letter ‘a’ qualifies as a valid value from a GWorkspace User search module, then the next module is a Create user. Once that is done for the first qualifying value of ‘a’, the scenario does not need to continue iterating over the remaining values in the array.

Is there a way to not eat up the resulting tasks of checking the remaining array values: b, c, d, & e?

It doesn’t appear that there is.

I tried using the “Break” module, but that only works on an error handler branch, not as a way of breaking out of an Flow Control Iterator.

Thanks

Hi @mixelpix,

I feel like you will need to artificially cause your scenario to error out.

Try adding a router after the module that checks if a user needs to be created.
After the Router, add a filter to check if the result of that check is “not already in use”. If not, route to the module that creates the user, then use this technique at the link above to end the scenario.

If the result is “already in use”, then it should go back to the Iterator because there’s nothing else to end the scenario.

I hope this helps and hope it works or gives you some ideas!

3 Likes

Hi @Donald_Mitchell,

I think that you’re correct. The deeper I dive into this, it just seems like it’s not in the interest of low/no-code platforms to offer something akin to the keyword, break’s function in Javascript… The sum loop operations are pre-defined by the bundles fed to it. It would be nice if there was a “while loop” that you could set termination conditions for… oh well.

FWIW, I am using a data store (I use the scenario’s execution id as the key for the duration of the run) and delete it when the brach is finished. The first module after the Iterator module checks for the existence of the record. This prevents downstream modules from getting run after a match is found, but for every bundle fed to the iterator, that record check eats up an operational task.

That seems like a good way to handle it too.
I suppose since you ultimately wanted to save Ops, you should use whichever would use less?

I suspect they had throw() or a similar function in the works for Integromat, but never added or completed it before creating Make. Who knows!

If you implement one method or the other, let us know how it works out and which you prefer if you end up trying both (if you wouldn’t mind, of course!)

3 Likes

Yes it is possible. Put filters and it will be make it not proceed and it will not consume any operations.
Before iterator set a custom variable to 0 and when you pass it and got what you need update that variable again to different value and use filter after the iterator to do not proceed if value is changed.

Have a look to this to update custom variable

3 Likes

@CodexSolutions is this Hamza? Thanks, but your “solution” does not apply to this question.

First of all, the search for a match is downstrem, so no matter what, I am iterating over the full set of possibilities because I do not know the exit condition going in.

Furthermore, downstream from the Iterator module, filtering with a custom variable doesn’t work within the loop - the custom variable’s value remains whatever it was when the scenario entered the iterator.

For example, starting with a boolean custom variable set to {{false}}

{{split(“a,a,a,b,a,a,a,a,a,a,a,a,a,a,a,a,a”; “,”)}}

If we only act to set upon the “b” value, we could, by your claim, end up with only four operations that pass the filter if we update the custom variable before the last step of a success case. Rather, all 17 bundles pass and operations accrue (which is what I am trying to avoid)

Step one set the custom variable in your org to {{false}}. Then, the scenario’s first module sets a variable (using the above split method). Next module is the iterator, using the value of the split. The next is a filter connection, only allowing for when the custom variable is {{false}}, the module it connects to is a Make Update Custom Variable which sets the variable to {{true}}. One the first run goes through and updates the custom variable, the filter does not update to the {{true}} value until after the scenario ends.

See here for an example (you’ll need to set up your own custom variable and connection to Make, of course).

{
    "name": "Integration Tools, Make",
    "flow": [
        {
            "id": 2,
            "module": "util:SetVariable2",
            "version": 1,
            "parameters": {},
            "mapper": {
                "name": "demo",
                "scope": "roundtrip",
                "value": "{{split(\"a,a,a,b,a,a,a,a,a,a,a,a,a,a,a,a,a\"; \",\")}}"
            },
            "metadata": {
                "designer": {
                    "x": 0,
                    "y": 0
                },
                "restore": {
                    "expect": {
                        "scope": {
                            "label": "One cycle"
                        }
                    }
                },
                "expect": [
                    {
                        "name": "name",
                        "type": "text",
                        "label": "Variable name",
                        "required": true
                    },
                    {
                        "name": "scope",
                        "type": "select",
                        "label": "Variable lifetime",
                        "required": true,
                        "validate": {
                            "enum": [
                                "roundtrip",
                                "execution"
                            ]
                        }
                    },
                    {
                        "name": "value",
                        "type": "any",
                        "label": "Variable value"
                    }
                ],
                "interface": [
                    {
                        "name": "demo",
                        "label": "demo",
                        "type": "any"
                    }
                ]
            }
        },
        {
            "id": 4,
            "module": "builtin:BasicFeeder",
            "version": 1,
            "parameters": {},
            "mapper": {
                "array": "{{2.demo}}"
            },
            "metadata": {
                "designer": {
                    "x": 300,
                    "y": 0
                },
                "restore": {
                    "expect": {
                        "array": {
                            "mode": "edit"
                        }
                    }
                },
                "expect": [
                    {
                        "name": "array",
                        "type": "array",
                        "label": "Array",
                        "mode": "edit",
                        "spec": []
                    }
                ]
            }
        },
        {
            "id": 6,
            "module": "make:updateAVariable",
            "version": 1,
            "parameters": {
                "__IMTCONN__": 1345572
            },
            "filter": {
                "name": "TEST",
                "conditions": [
                    [
                        {
                            "a": "{{var.organization.zPDKtest}}",
                            "o": "boolean:equal",
                            "b": "{{false}}"
                        }
                    ]
                ]
            },
            "mapper": {
                "select": "organization",
                "variableName": "zPDKtest",
                "typeId": "3",
                "value": "{{true}}",
                "organizationId": 24027
            },
            "metadata": {
                "designer": {
                    "x": 600,
                    "y": 0
                },
                "restore": {
                    "parameters": {
                        "__IMTCONN__": {
                            "label": "YOUR CONNECTION",
                            "data": {
                                "scoped": "true",
                                "connection": "make"
                            }
                        }
                    },
                    "expect": {
                        "select": {
                            "label": "Organization"
                        },
                        "typeId": {
                            "mode": "chose",
                            "label": "Boolean"
                        },
                        "organizationId": {
                            "mode": "chose",
                            "label": "YOUR ORG"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "__IMTCONN__",
                        "type": "account:make",
                        "label": "Connection",
                        "required": true
                    }
                ],
                "expect": [
                    {
                        "name": "select",
                        "type": "select",
                        "label": "Variable in Organization/Team",
                        "required": true,
                        "validate": {
                            "enum": [
                                "organization",
                                "team"
                            ]
                        }
                    },
                    {
                        "name": "variableName",
                        "type": "text",
                        "label": "Variable Name",
                        "required": true
                    },
                    {
                        "name": "typeId",
                        "type": "select",
                        "label": "Type",
                        "required": true,
                        "validate": {
                            "enum": [
                                "1",
                                "2",
                                "3",
                                "4"
                            ]
                        }
                    },
                    {
                        "name": "value",
                        "type": "text",
                        "label": "Variable Value",
                        "required": true
                    },
                    {
                        "name": "organizationId",
                        "type": "select",
                        "label": "Organization ID",
                        "required": true
                    }
                ]
            }
        }
    ],
    "metadata": {
        "instant": false,
        "version": 1,
        "scenario": {
            "roundtrips": 1,
            "maxErrors": 3,
            "autoCommit": true,
            "autoCommitTriggerLast": true,
            "sequential": false,
            "confidential": false,
            "dataloss": false,
            "dlq": false,
            "freshVariables": false
        },
        "designer": {
            "orphans": []
        },
        "zone": "us1.make.com"
    }
}

Not sure what you mean by this?

Anyway, if that works for you and you’re on the Pro plan or higher, then great!

Another comment on your scenario:
Since your Scenario starts with an array of possible values, and you just need to find the first one that’s not in use, then you may have another option.
In your second module, query Google for a list of existing users. You may need to aggregate this into an array.
In the third module, the one that creates the user, use the remove() function on your first array (of possible names), and submit the list of users that already exist as the list of values you want to remove from that array.
The result of the function will leave you an array of possible users not already in use.
Then, just take the first element of that new array and create the new user.

This method wouldn’t use an Iterator and therefore would use the same number of Ops every time it runs, which is really not that many, probably around 4 Ops.

This method would also work for Free or Core users since they don’t have to use a Custom Variable.

2 Likes

my bad - wrong @ - I meant to tag Codex (note the “reply to CodexSolution”). Hamza is a user in a different forum who posted this “increment by 1” example as if were applicable to my question. It is not.

The answer to the question, " How do I stop the iterator module mid-iteration?" is resoundingly: you can’t.

Whatever bundles are fed to the array, it will process each one in any downstream modules.

There is no stopping it.

As a more concrete example, let’s say I have an array of [a, b, c, d, e] which I turn into bundles.

I iterate over the bundles one item at a time with the downstream branch from the iterator module.

Let’s say the first letter ‘a’ qualifies as a valid value from a GWorkspace User search module, then the next module is a Create user. Once that is done for the first qualifying value of ‘a’, the scenario does not need to continue iterating over the remaining values in the array.

Is there a way to not eat up the resulting tasks of checking the remaining array values: b, c, d, & e?

It doesn’t appear that there is.

if this is your case , my solution is the way to go I am willing to jump on a call , to dicuss more and see internally ,

may be you are not using it correctly

let me know ,thank you

In this example my Iterator iterates through 8 names:

For each name, we try to find the record in SmartSuite.
If it exists, then it moves on to the next name.
If it doesn’t exist, it will proceed to the error route, which is SmartSuite Create a Record.
Now that my record has been created, it moves on to the next JSON module which I have intentionally configured to error out, then that takes an error route to the Ignore module.
The end result of the Scenario is Complete/Successful and the Scenario ended after the 4th Iteration, as a record could not be found for that name.

Total operations for this run was 7.

So if I had 8 names to Iterate, plus all those modules after the Iterator, there’s no way my Iterator went through all 8 names if the Scenario only consumed 7 Ops.

In this way, you can stop the Iterator midway, by intentionally creating an error condition. You are correct though, it’s not straightforward and it is a roundabout way to do it.

2 Likes

It’s not that there is not a “straightforward” way. It is that the answer to the question asked, " How do I stop the iterator module mid-iteration?" is resoundingly, “No.”

End of story.

To be fair you asked “is there a way”. I gave you a way. Did my Iterator go through all 8 names? No it did not. The scenario did nothing with the remainder of the names. I think that qualifies as mid-iteration.

Take it or leave it, if you want more info to help apply to your Scenario, happy to provide it. Otherwise, sorry we didn’t provide satisfactory answers, and have a great day. :wave:

This is a community, so hopefully it helps you or someone else, that’s the only goal here.

3 Likes

Hey, this is something new for me even I have been using Integromat / Make few years. Thanks!

1 Like