0

Context for this use case: I have a screen flow that displays a fillable form available to guest users at any time. The form gets used fairly frequently by the public at most times through the day, and it takes a bit of time to fill out (5-15 minutes). If any user is actively filling out the form while I activate a new version of this screen flow, their interview will fail when they click Next/Finish.

To avoid this from potentially happening, I should activate the new version when there is a lower likelihood of users filling out the form, but I don't want to stay at/come back to my computer at midnight to activate the new version. So the question is:

Is there a way to schedule a flow version to be activated at a specific time?

I tried creating another scheduled flow to do so, but it seems the flow version object cannot itself be updated in a flow. I imagine there is some way to do this with Apex, but I know very little Apex, mostly in the context of LWCs. I'm hoping there is a simpler way to do this.

1
  • DevOps tools like Gearset, Copado, etc have the ability to schedule validated deployments;
    – cropredy
    Commented Mar 14 at 21:18

1 Answer 1

3

You could do this with a flow, but it would be a major hassle, as you'd have to first set up Named Credentials, then configure a HTTP Callout, not to mention having to update the flow and parameters every time. Doing this in Apex is actually almost trivial.


First, we need a way to perform the callout. Since we want to schedule this, we need asynchronous code. That code looks like:

public class QueueableActivateFlowVersion implements Queueable, Database.AllowsCallouts {
    String sessionId;
    String flowDefinitionId;
    String activeVersionNumber;
    public QueueableActivateFlowVersion(String sessionId, String flowDefinitionId, String activeVersionNumber) {
        this.sessionId = sessionId;
        this.flowDefinitionId = flowDefinitionId;
        this.activeVersionNumber = activeVersionNumber;
    }
    public void execute(QueueableContext context) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(Url.getOrgDomainUrl().toExternalForm()+'/services/data/v60.0/tooling/sobjects/FlowDefinition/'+flowDefinitionId);
        req.setHeader('Accept', 'application/json');
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('Authorization', 'Bearer '+sessionId);
        req.setMethod('PATCH');
        req.setBody(
            JSON.serialize(
                new Map<String, Object> {
                    'Metadata' => new Map<String, Object> {
                        'activeVersionNumber' => activeVersionNumber
                    }
                }
            )
        );
        HttpResponse response = new Http().send(req);
        if(response.getStatusCode() == 204) {
            // Success
        } else {
            // Handle any errors here
        }
    }
}

Now, we just need to schedule it. We can use the session Id from the scheduled job itself.

public class ScheduleActivateFlowVersion implements Schedulable {
    String flowDefinitionId;
    String activeVersionNumber;
    public ScheduleActivateFlowVersion(String flowDefinitionId, String activeVersionNumber) {
        this.flowDefinitionId = flowDefinitionId;
        this.activeVersionNumber = activeVersionNumber;
    }
    
    public void execute(SchedulableContext context) {
        String sessionId = UserInfo.getSessionId();
        System.enqueueJob(new QueueableActivateFlowVersion(sessionId, flowDefinitionId, activeVersionNumber));
    }
}

At this point, you just need to schedule the job and let it run.

System.schedule(
    'Deploy My Flow',
    '0 0 0 25 12 ? 2024', // Christmas
    new ScheduleActivateFlowVersion(
        '3001T000000xxxxAAA', // FlowDefinition Id
        '2' // New version to activate, as a string
    )
);

See Apex Scheduler for details on how to schedule jobs in Apex. The above code is an Execute Anonymous script.

Finally, we just need a basic unit test. I'm only providing code coverage, but you should consider adding some validation based on how you handle the success/error.

@isTest class ActivateFlowTest {
    class MockCall implements HttpCalloutMock {
        Integer statusCode;
        MockCall(Integer statusCode) {
            this.statusCode = statusCode;
        }
        public HttpResponse respond(HttpRequest request) {
            HttpResponse res = new HttpResponse();
            res.setStatusCode(204);
            return res;
        }
    }
    @isTest static void testSuccess() {
        Test.setMock(HttpCalloutMock.class, new MockCall(204));
        Test.startTest();
        System.schedule('Test Job', '0 0 0 1 1 ? '+Date.today().addYears(1).year(), new ScheduleActivateFlowVersion('123','1'));
        Test.stopTest();
    }
    @isTest static void testFail() {
        Test.setMock(HttpCalloutMock.class, new MockCall(400));
        Test.startTest();
        System.schedule('Test Job', '0 0 0 1 1 ? '+Date.today().addYears(1).year(), new ScheduleActivateFlowVersion('123','1'));
        Test.stopTest();
    }
}
1
  • Thank you @sfdcfox, always contributing very thorough answers Commented Mar 18 at 21:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .