How To Create a Workflow Using CronDock

In this post we are going to develop a simple workflow using CronDock

After signing up the CronDock web portal will provide you with an "API key" which can be used to call the CronDock RESTful API. Note that at this moment you can only communicate with CronDock through our API. Using the API key you can call the CronDock via different tools such as "curl", python libraries such as "requests" or tools such as postman .

The CronDock API end point is https://api.crondock.com/. Keep in mind that in all your API calls to CronDock API endpoint, you should add your "API key" in a Header called "Authorization" and you need to add "Api-Key " at its begining. So for instance in "curl" you will have something like (replace XXXXX with your "API key"):


curl -X GET -H "Content-Type: application/json" -H "Authorization: Api-Key XXXXX" https://api.crondock.com/workflow/
                
Or in python:
import requests

headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Api-Key XXXXX',
}

response = requests.get('https://api.crondock.com/workflow/', headers=headers)
                

Now, let's define a "Workflow", a workflow is a collection of "Tasks" (read this post to learn more about tasks) that have dependencies with each other. For instance let's say you want to automatically check whether your website is up or not every day and if it is down you want to receive a slack message. In this case you want to first run a task that sends a request to your website, and if the request failed you want to spin up another task that sends you a slack message notifying you that the website is down. In this example the second task has a dependency to the first task and it only runs when the first task fails. In such cases you can use a workflow.

To create a workflow using CronDock, you need to submit a POST request to /workflow/ endpoint and pass the tasks (and other workflow parameters) as part of the payload. The workflow parameters are as follow:

      name: a name for your workflow, note that this name will get updated with a suffix by the system to avoid having the same name for different runs.
      type: the type of the workflow which can be either simple or cron, note that simple workflows run only once after being created and cron workflows run frequently based on the provided schedule
      schedule: the schedule to run the cron workflows. This should be a string that defines the schedule of the workflow and should follow the cron format (you can read more about cron format here: https://crontab.guru/). Note that this only can be used in workflowss with type set as cron.
      tasks: a list of tasks to run as part of the workflow. The format for each task is very similar to the format of simple tasks (again, read this post to learn more about simple tasks) with only one new element which is dependencies. We will discuss the task section and task dependencies more below.
For each task we have the following parameters:
      name: a name for the task, this name will be used to define the dependencies.
      image: path to the container image you want to run, note that with a free account you can only run public images and you need a basic or enterprise account for running images from private repositories.
      args: the argument to pass to the container, note that the arguments should be provided as a list of string values.
      dependencies: a string to define the dependencies for the task to run. Dependency to another task should be defined in {task-name}.{status} format where {task-name} is the name of another task that this task is dependent on and the {status} is the final status of that task for which this task should run. The {status} can be either succeed or failed. Note that you can also have multiple dependencies by using & (as and) , | (as or) operators and ! (as not) operators. For instance if the task is dependent on 3 tasks and should run only if the first task (named task-1) succeed and one of the second task (named task-2) or third task (named task-3) failed, the dependency would look like this: "task-1.succeed & (task-2.failed | !task-3.succeed)".
So let's create a workflow on CronDock. We want our workflow to check whether https://crondock.com is up or down on daily basis and send us a message on slack if it is down. In our example we are going to use slack incoming webhook to send message to slack. We are also going to use the official public image of curl from docker hub (curlimages/curl:latest) to send requests to CronDock and send messages to slack via the webhook. You can learn more about the official curl docker image here.

The first step is to create an incoming webhook for your slack channel. You can follow this simple insturction from slack to create an incoming webhook. Sending messages to slack via webhook is very easy, you only need to push a POST request like this to the webhook:

curl -X POST --data-urlencode "payload={\"text\":\"Hello, World! \"}" https://hooks.slack.com/services/XXX/XXXX
                  
Where https://hooks.slack.com/services/XXX/XXXX is the webhook you have created for your channel, and text in the payload is the message you want to send to slack. Run it and you will recive receive a "Hello, World!" message on your slack channel.

So having that we need to create a workflow with two tasks, one that sends a GET request to https://crondock.com and one that pushes a POST request to our slack webhook with a text like "Your website is down!". The seconds task should run only if the first task fails, so we will have a dependency for the second task to run only if the first task failed.

We want our workflow to run on daily basis, so we should set the workflow type to cron and the schedule to something like "30 2 * * *" which means run the workflow at 02:30 AM UTC every day.

To make sure that we are going to get the slack message through the second task we can first create a simple task and test it using that. The task can be something like this (replace Api-Key XXXXX with your Api Key and https://hooks.slack.com/services/XXX/XXXX with your slack webhook url):

 curl -X POST -H "Content-Type: application/json" -H "Authorization: Api-Key XXXXX" -d '{
 "name": "slack-test",
 "image": "curlimages/curl:latest",
 "args": ["--data-urlencode", "payload={\"text\":\"Your website is down! \"}" , "https://hooks.slack.com/services/XXX/XXXX"],
 "type": "simple"
 }' https://api.crondock.com/task/

And you should receive a message on your slack channel like this:

So based on our discussion above you can create the workflow like this:

 curl -X POST -H "Content-Type: application/json" -H "Authorization: Api-Key XXXXX" -d '{
 "name": "check-crondock-website",
 "type": "cron",
 "schedule": "30 2 * * *",
 "tasks":[
     {
     "name": "task-1",
     "image": "curlimages/curl:latest",
     "args": ["-L", "-v", "https://crondock.com"],
     "dependencies": ""
     },
     {
     "name": "task-2",
     "image": "curlimages/curl:latest",
     "args": ["--data-urlencode", "payload={\"text\":\"Your website is down! \"}" , "https://hooks.slack.com/services/XXX/XXXX"],
     "dependencies": "task-1.failed"
     }
 ]
 }' https://api.crondock.com/workflow/

Now looking at created workflows we have:

curl -X GET -H "Content-Type: application/json" -H "Authorization: Api-Key XXXXX" https://api.crondock.com/workflow/
{"count":1,"next":null,"previous":null,"results":[
  {
    "id":1,
    "tasks":[
      {
        "id":1,
        "created_at":"2022-07-20T01:05:17.966297Z",
        "name":"task-1",
        "image":"curlimages/curl:latest",
        "args":["-L","-v","https://crondock.com"],
        "dependencies":"",
        "user":2,
        "workflow":1
      },
      {
        "id":2,
        "created_at":"2022-07-20T01:05:17.976800Z",
        "name":"task-2",
        "image":"curlimages/curl:latest",
        "args":["--data-urlencode","payload={\"text\":\"Your website is down! \"}","https://hooks.slack.com/services/XXX/XXXX"],
        "dependencies":"task-1.failed",
        "user":2,
        "workflow":1
      }
    ],
    "created_at":"2022-07-20T01:05:17.786737Z",
    "name":"check-crondock-website-rtoatd",
    "type":"cron",
    "schedule":"30 2 * * *",
    "user":2
  }
]}

Now after the workflow runs we can take alook at its results so far. Note that in the above we have "id":1 for the workflow, we can get the results for all the workflows by submitting a GET request to /result/ endpoint. When we want to get the results for a specific workflow we can filter the results by passing the workflow. For instance for the workflow above with "id":1 we can pass ?workflow=1 in the url. So we are going to have:

 curl -X GET -H "Content-Type: application/json" -H "Authorization: Api-Key XXXXX" https://api.crondock.com/result/?workflow=1
 {"count":1,"next":null,"previous":null,"results":[
  {
    "id":1,
    "results":[
      {
        "id":9,
        "created_at":"2022-07-20T02:30:05.319748Z",
        "name":"task-1-bsrukc",
        "image":"curlimages/curl:latest",
        "args":["-L","-v","https://crondock.com"],
        "type":"workflow",
        "schedule":"",
        "user":2,
        "workflow_task":1,
        "workflow_result":1,
        "secret":null
      }
    ],
    "created_at":"2022-07-20T02:30:03.691986Z",
    "user":2,
    "workflow":1
  }]
}

So based on the results, for that workflow so far one task have been ran with "id":9 and based on the name it was the task-1 from the workflow. Note that the system will add a randomly generated sequence of alphabet as a suffix of the name to avoid using similar names for the same tasks.

So now let's pull more information on that task:

curl -X GET -H "Content-Type: application/json" -H "Authorization: Api-Key XXXXX" https://api.crondock.com/task/9/
{"count":1,"next":null,"previous":null,"results":[
  {
    "id":9,
    "created_at":"2022-07-20T02:30:05.319748Z",
    "name":"task-1-bsrukc",
    "image":"curlimages/curl:latest",
    "args":["-L","-v","https://crondock.com"],
    "type":"workflow",
    "schedule":"",
    "user":2,
    "workflow_task":1,
    "workflow_result":1,
    "secret":null,
    "results":[
      {
        "status":{
          "start_time":"2022-07-20 02:30:05+00:00",
          "phase":"Succeeded"
        },
        "metadata":{
          "name":"task-1-bsrukc-9fck2"
        }
      }]
    }]
  }

Based on the "phase":"Succeeded" in the status section, task-1 was successful, meaining it was able to load the website so the website was up and running. As a result, since the condition we have for dependencies in task-2 is "task-1.failed", that task did not meet the condition and as expected task-2 didn't run and we didn't get any message regurding the website being down on slack.

If needed we can also pull the full output of the task by passing log=true in the url like This:

curl -X GET -H "Content-Type: application/json" -H "Authorization: Api-Key XXXXX" https://api.crondock.com/task/9/?log=true

and that will show the html code of the website pulled by the task.

This article shows how you can create a workflow on CronDock. Please let me know if you have any question at support@crondock.com

I also have a good document which provides more detailed information on all the requests you can make to CronDock API.