Trigger CC from Another Task

A CloudCode task can be queued for execution from itself, or from another task. This can be used to:

  • Split a long-running task into smaller pieces to avoid running into time limits.

  • Prevent multiple instances of a task running concurrently.

  • Re-use logic by keeping it in a shared task (e.g. sending an email).

  • Run multiple instances of a task in parallel (although most use cases can be covered by doing parallel execution in a single task).

From the CloudCode task's JavaScript we call othertask (the name of the other CloudCode task) like this:

await CloudCode.scheduleTask({task: 'othertask', parameters: {myvalue: 42}});

In othertask we have the following:

export async function run(params) {
    console.log('myvalue', params.myvalue);
}

Options for CloudCode.scheduleTask:

  • task (string): The name of the task to execute. The task will be executed in the same environment.

  • parameters (object, optional): Parameters to pass to the task. Must be an object. The object will be converted to JSON and back.

  • at (Date, optional): Time to run the task.

  • after (number, optional): Milliseconds delay before executing the task.

  • queue (string, optional): Name of a queue to run the task on. No two tasks in the same queue will ever run concurrently. If no queue name is passed, multiple instances of the task may run concurrently. The enqueued task is scheduled to run in a completely separate process. No memory is shared between the two.

Because of the JSON conversion step, database objects cannot be passed through directly in the parameters. It is recommended to instead pass the object ID, and do a database lookup in the enqueued task.

Retries

When a task is placed on a queue, CloudCode ensures that it is run at least once. A task's execution could fail in some scenarios, in which case the task will be retried. A task is considered to have run successfully and will not be retried if a response (either error or success) is received from the task.

The following scenarios will not generate a response, and will cause the task to be retried:

  • Connection failure between the queue runner and the task

  • Task timeout

  • Task crash due to for example out-of-memory error or process.exit()

Due to these cases, all tasks placed on a queue must be designed to handle multiple executions with the same parameters. If it is important that an action is performed only once, a flag can be stored in the database to indicate that the task has already started or been completed, and should not be executed again.

// Typical pattern for task execution, keeping track of task state.

export async function run(parameters) {
    // taskstate is a model defined in the data-model to keep track of the
    // execution.
    let taskstate = await DB.taskstate.first(parameters.state_id);
    if(taskstate.status == 'complete') {
        console.log('task is already completed');
        return;
    } else if(taskstate.status == 'started') {
        console.log('task has been started previously');
        // The task has previously been started, but has not
        // completed for some reason.
        // It is to the developer to decide what to do here.
        // If the task can be resumed or re-run, continue running
        // here. If manual entervention may be required, rather
        // stop execution here.
    }

    taskstate.status = 'started';
    await taskstate.save();

    try {
        // perform task here


        taskstate.status = 'complete';
        await taskstate.save();
    } catch(error) {
        // Something went wrong. Save the error.
        taskstate.error = error.message;
        await taskstate.save();

        // Retry logic could also be implemented here, for example:
        if(taskstate.tries_remaining > 0) {
            taskstate.tries_remaining -= 1;
            taskstate.save();
            CloudCode.scheduleTask({task: this.name, parameters: parameters});
        }
    }
}

Last updated