Responding to action results

Sometimes, you'll want to do more than a single round of generating actions – you may want to check the results of an action, see if they appear the way you expect, and then perform additional actions based on the results.

To achieve this flow, subscribe to the "mechanic/actions/perform" topic. When a task includes this subscription, Mechanic will generate an event with that topic for every action that the task completes.

This strategy is commonly used with the "http" action, for reading data from third-party APIs. (For more on that specific use case, see Can I load data from external sources?)

Variables

Events with the topic "mechanic/actions/perform" are, by nature, always child events (see Parent and child events). As such, their event variable contains a "parent" property. This means you may use event.parent.data to access all the data that was used to create the action with which the current child event is associated.

Task runs also receive the action variable (named after "actions" in "mechanic/actions/perform", and mirroring the contents of event.data – a standard pattern for events that are associated with a singular subject). This variable has the following attributes:

  • type – a lowercase string, defining the action type
  • options – the options with which the action was configured
  • run – an object containing the following attributes, describing the run that was generated by the action's performance
    • id – a string containing the UUID for this action
    • ok – a boolean, true for a successful action run, and false for a failure
    • error – either null, or a string containing the error message returned for a failed action
    • result – the data returned from the action; format varies by action type
    • result_meta – an object containing useful performance-related data
    • attempts – an integer, indicating the number of times the action was attempted before final success or failure
    • enqueued_at – the time at which this action was sent to our queue for execution
    • started_at – the time at which the action started
    • stopped_at – the time at which the action stopped
    • elapsed_time_ms – the number of milliseconds this action required, from start to stop

Usage warning

It's important to specifically account for the "mechanic/actions/perform" topic when writing your task script, minding the fact that improper composition could result in an infinite loop. (Having said that, Mechanic will step in and forcibly fail subsequent task runs that contain results identical to their predecessors.)

Remember, you can use "log" tags to return data without requiring an action.

Example task

This example prompts the Mechanic user to enter a chunk of JSON, which will be used to create a customer record via a "shopify" action. If Shopify reports back that the customer creation was successful, the task will generate an "echo" action, reporting the success. If not, another "echo" will be generated, reporting the specific error message from Shopify.

Subscriptions

mechanic/user/text
mechanic/actions/perform

Script

Note: This script is written to specifically support preview actions, generating stub data during event preview to ensure that appropriate preview actions are generated.

{% if event.topic == "mechanic/user/text" %}
  {% if event.preview %}
    {% assign event = hash %}
    {% assign event["topic"] = "mechanic/user/text" %}
    {% assign event["data"] = '{"email":"customer@example.com"}' %}
  {% endif %}

  {% assign data = event.data | default: "{}" | parse_json %}
  {% action "shopify", "create", "customer", data %}
{% elsif event.topic == "mechanic/actions/perform" %}
  {% if event.preview %}
    {% assign action = hash %}
    {% assign action["type"] = "shopify" %}
    {% assign action["run"] = hash %}
    {% assign action["run"]["ok"] = true %}
  {% endif %}

  {% if action.type == "shopify" %}
    {% if action.run.ok %}
      {% action "echo", "Success!" %}
    {% else %}
      {% action "echo", "Invalid data!", action.run.error %}
    {% endif %}
  {% else %}
    {% comment %}
      This branch is where the task ultimately terminates. At
      this point, we're still processing performed actions, but
      we know that the action type here must be something other
      than our initial "shopify" action. And clearly, it's
      "echo", and we don't need to do anything with it. This
      final task run will therefore perform no actions, which
      means that the run sequence will finally conclude.

      For the purposes of demonstration, we'll log the data from
      our parent event, illustrating that we do have full
      knowledge of context here.
    {% endcomment %}

    {% log parent_event_data: event.parent.data %}
  {% endif %}
{% endif %}
Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.