Preventing the Cloudcode task from retrying before timeout is triggered

Hi Developers,

We are trying to prevent a CloudCode task from retrying when it times out. We have successfully registered the before Timeout and we can see that it is indeed being triggered. We are however not sure how to stop the task once this is triggered. We tried to throw an error for the task to fail, but this just displays the error and does not stop the task. How would we stop the task?

Existing code:

    this.on('beforeTimeout', () => {
        rollbar.critical(`${CloudCode.task.name} - Script timeout imminent!`, { custom: { context: JSON.parse(JSON.stringify(this)), params: params } });
        throw Error (`${CloudCode.task.name} - Script timeout imminent!`);
        console.log("Error: Script timeout imminent! Stopping the task now.");
        return;
    });

Output:

07:05:21.326 [TASK:ERROR] Uncaught: Error: api_validate_bank_heartbeat - Script timeout imminent!
    at TaskContext.Error (/var/task/app/cloudcode/api_validate_bank_heartbeat/index.js:33:15)
    at TaskContext.emit (events.js:314:20)
    at TaskMonitor.collect (/var/task/app/cloudcode/api_validate_bank_heartbeat/node_modules/@journeyapps/cloudcode/src/TaskMonitor.ts:54:12)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)
07:05:21.419 [TASK:WARN] WARNING: The task is running over the time limit. Reduce the amount of work done per task.
07:05:21.422 [TASK:ERROR] Uncaught: Error: api_validate_bank_heartbeat - Script timeout imminent!
    at TaskContext.Error (/var/task/app/cloudcode/api_validate_bank_heartbeat/index.js:33:15)
    at TaskContext.emit (events.js:314:20)
    at TaskMonitor.collect (/var/task/app/cloudcode/api_validate_bank_heartbeat/node_modules/@journeyapps/cloudcode/src/TaskMonitor.ts:54:12)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)
07:05:21.520 [TASK:WARN] WARNING: The task is running over the time limit. Reduce the amount of work done per task.
07:05:21.523 [TASK:ERROR] Uncaught: Error: api_validate_bank_heartbeat - Script timeout imminent!
    at TaskContext.Error (/var/task/app/cloudcode/api_validate_bank_heartbeat/index.js:33:15)
    at TaskContext.emit (events.js:314:20)
    at TaskMonitor.collect (/var/task/app/cloudcode/api_validate_bank_heartbeat/node_modules/@journeyapps/cloudcode/src/TaskMonitor.ts:54:12)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)
07:05:21.620 [TASK:WARN] WARNING: The task is running over the time limit. Reduce the amount of work done per task.
07:05:21.622 [TASK:ERROR] Uncaught: Error: api_validate_bank_heartbeat - Script timeout imminent!
    at TaskContext.Error (/var/task/app/cloudcode/api_validate_bank_heartbeat/index.js:33:15)
    at TaskContext.emit (events.js:314:20)
    at TaskMonitor.collect (/var/task/app/cloudcode/api_validate_bank_heartbeat/node_modules/@journeyapps/cloudcode/src/TaskMonitor.ts:54:12)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)

Hi @Tertius

The answer depends on what your task is doing at the point when it is about to run out of time? Can you share more details on what your task is doing, or do you just want to get some pointers in general?

In short, you need to get your task to finish what it is doing before the time runs out. Most people manually track the duration of the task and then they implement code to stop the process once it reaches about 4mins. At this point they would then reschedule the task to start again, but either pass in updated params or update the DB to allow the subsequent iteration(s) to not start from scratch but rather continue where the previous one left off (obviously the actual task code needs to be able to handle this kind of ‘continue’ logic as well)

I will get a more complete answer with some example patterns to you in a couple of days, but thought to at least share this much so long - sorry for the delay

Hi @tielman,

So we can’t utilise the callback function to stop the task from running and we’ll have to implement our own logic?

@Tertius You can definitely use it, but just not on it’s own. Unfortunately there is currently no prebuilt way of simply stopping the task, so you’ll have to build in a mechanism for stopping your task and then you can trigger that mechanism from the callback.

Something like this (credit to @ralf)

export async function run() {
    // start our timeout mechanism as false
    let timingOut = false;
    
    // in the timeoutCallback we set the mechanism to true
    this.on('beforeTimeout', () => {
        timingOut = true;
    });

    // here is a loop that is doing a lot of work that will maybe cause the task to run out of time
    while (true) {
        // the first thing I check in my loop is if the timeout mechanism is true
        if (timingOut) {
          // mechanism is true so now I need to break the loop
          break;
        }

        console.log('Doing lots of work');

        // this promise just allows my while loop to trigger the beforeTimeout
        // THIS IS JUST A SIMULATION OF WORK
        // REMOVE IN YOUR IMPLEMENTATION
        await new Promise(resolve => setTimeout(resolve, 1000));
    }
}

I hope this helps

More complete example