Coding Execute Operations

Execute operations run when an action is run, manually or automatically. This is where most of the action logic is written and most external API calls are made.

An execute operation generally contains code that:

  • Runs any necessary logic, passing through parameters it has defined
  • Retrieves data from operations that call external integrations
  • Formats our response message so that it is useful for the user
  • Posts that response message to the activity time and in Slack

An operation calling external integrations generally contains code that:

  • Makes calls to external APIs, sometimes based on user input

Typically, these are named based on the operations they are taking with a connector.

Specifying and retrieving inputs#

The parameters sidebar (located on the right side) is where you specify any inputs your operations require. For the specifically deployed execute operation, these parameters are special in that they will appear in the runbook edit page for the runbook author to pre-configure. They may also appear at runbook runtime for the user to fill in.

Make sure you also have a parameter of type object named context in your execute operation, as well as in your input prompt operation if you choose to use one. This parameter is automatically passed through and contains information like the activity id and team name.

context = params.get("context")
input_param_1 = params.get("input_param_1")

Posting messages and specifying output parameters#

Use workflow.log.done({display}, standardOutputParams={}, customOutputParams={}) to log results and mark the successful completion of an entire action run. These logs will show up automatically in the runbook run and in any connected activity and Slack channels.

The customOutputParams object in the done or fail logs, along with the developer-defined schema, allow your action output to be passed through to subsequent actions in the chain.

custom_output_params = {"output_1": "this can be passed to subsequent actions"}
workflow.log.done("Restarted ECS instance", {}, custom_output_params)

Make sure to always include a done in your action, and a fail if appropriate.

See more about logging in the Python operations doc.

Long-Running Actions#

Execute operations are limited to one minute of running time, which is configurable to a maximum of five minutes. Operations sometimes need more time than this to, for example, poll an external service for completion of a request.

Long-running actions allow an action’s execute operation to schedule a future operation on the same action (called a continuation) to occur at a specified time. Each continuation may schedule another continuation. In this way, an action can continue indefinitely. When a long-running action does not need to schedule another continuation, it ends by calling either workflow.log.done() or workflow.log.fail() just like any other action.

Schedule a continuation#

Schedule a continuation for a specific time expressed as an ISO-8601 time string:

task.create("operation_name", parameters).continueAt("2022-01-09T08:43:00-08:00")

Schedule a continuation to run after a certain amount of time:

task.create("operation_name", parameters).continueAfter(2, "MINUTES")

Valid time units are SECONDS, MINUTES, HOURS, DAYS, and WEEKS.

Pass parameters to a continuation#

The parameters passed to task.create() are an ordinary map object. For example, if an operation takes the following parameters:

name (STRING)
age (INTEGER)

...the parameters map looks like this:

parameters = {
"name": "Stephen Dedalus",
"age": 22`
}

Example action#

This execute operation takes parameters telling it how many times to continue and the number of seconds to elapse between each continuation. Each time it runs, it subtracts one from count and schedules another continuation. When count reaches zero, instead of scheduling another continuation, it calls workflow.log.done().

def execute(params):
count = params["count"]
delay = params["delay"]

if count > 0:
report = "count = {}, delay = {}".format(count, delay)
workflow.log.status(report)

parameters = {
"count": count - 1,
"delay": delay
}

continuation = task.create("this.execute", parameters)
continuation.continueAfter(delay, "SECONDS")
else:
workflow.log.done("Long-running action finished!")

return {}

If this action is run with the parameters count=3, delay=10, it will produce the following series of status messages in the activity timeline, with 10 seconds elapsing from each message to the next:

count = 3, delay = 10
count = 2, delay = 10
count = 1, delay = 10
Long-running action finished!

The Run a Jenkins job action is an example of a long-running action.