1

We have an autolaunched flow that we would like to run on a schedule. I have created an apex class to do so, but when testing the class, I discovered that it is encountering errors only associated with a newer version of the flow still in development that is not active yet.

The documentation for the interview start method mentions that the behavior may be different depending on who invokes it.

When a flow user invokes an autolaunched flow, the active flow version is run. If there’s no active version, the latest version is run. When a flow admin invokes a flow, the latest version is always run.

I feel like this is coupling the flow version too closely to the permissions of the user scheduling the job. We would not only need to be careful of who schedules the job, but of reverting to older flow versions too. It would be too easy for someone to forget or not know this idiosyncrasy and make a change that unknowingly starts running the wrong logic in production.

Is there a better way to do this that does not entangle flow versions with user permissions?

1

Update: There is a Salesforce-provided feature that allows scheduling of flows coming with the Winter '20 release. https://releasenotes.docs.salesforce.com/en-us/winter20/release-notes/rn_forcecom_flow_fbuilder_start.htm


We ultimately implemented the flow in apex for unrelated reasons, but I did find a couple solutions for scheduling flows. In case anyone else is hoping to do something like this, here is what I found.

Flow versioning is always respected if it is started by a non-flow-admin, a user who does not have the "Manage Flow" system permission. They can not run a flow that is not active.

For flow admins, who do have the "Manage Flow" permission, whether the flow respects the active version or uses the most recent version depends on how the flow was started. If a flow admin starts a flow via the Interview.start method in Apex, via the flow URL, or via the "Run" button on the flow's setup page, then the flow will run the most recent version, even if it is not active. Flows can also contain a subflow element that starts another flow. If the main flow was started by an admin in any of these ways, then all subsequent subflows will also run the most recent version.

Autolaunched flows can also be started by Process Builder or the REST API. A scheduled job is Apex, so we can safely schedule a flow if we can invoke a Process Builder or the REST API from Apex.


Solution 1: use Apex to make a callout to the REST API endpoint for starting flows.

global class SchedulableFlow implements Schedulable {

    global void execute(SchedulableContext context) {
        String flowName = 'myFlow';
        String inputs = '{"inputs":[{"inputVar":"value"}]}'; // Set appropriately for your flow

        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(Url.getOrgDomainUrl().toExternalForm() + '/services/data/v45.0/actions/custom/flow/' + flowName);
        request.setMethod('POST');
        request.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        request.setHeader('Content-Type' ,'application/json');
        request.setHeader('content-length', String.valueOf(inputs.length()));
        request.setBody(inputs);

        HttpResponse response = http.send(request);

        // do something to handle requests that fail
    }
}

Solution 2: use a Process Builder to start the flow, and invoke the process from Apex (via Platform Events).

Process Builders can't directly be invoked by Apex, but they can be invoked by record changes, other Process Builders, or Platform Events. We could tie the process to a record change, and make that change in Apex to start it, but then we are coupling to a record. Thus we use Platform Events.

Create a Platform Event (for these purposes it doesn't need to be integrated with anything else or contain any custom fields). Create a Process Builder which starts when that event occurs. Add an action to the process that will launch your flow. Publish the event from Apex.

global class SchedulableFlow implements Schedulable {

    global void execute(SchedulableContext context) {
        List<My_Platform_Event__e> events = new List<My_Platform_Event__e>();
        events.add(new My_Platform_Event__e());

        // Call method to publish events
        List<Database.SaveResult> results = EventBus.publish(events);

        // Inspect publishing result for each event
        for (Database.SaveResult sr : results) {
            // do something to handle events that failed to publish       
        }
    }
}
  • Solution 1 is pretty clever – cropredy May 16 at 6:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.