Camunda-Robotframework-Workshop

This repo contains the exercises for the Workshop: Orchestrating Robot Tasks with Camunda Platform at Robocon 2022

MIT License

Stars
5

Camunda-Robotframework-Workshop

Welcome to the Workshop: "Orchestrating Robot Tasks with Camunda Platform". The workshop is hold at Robocon 2022. But you can follow the exercises here as well. The README contains the detailed instruction on how to complete the exercises. In the solution folder you find for every exercise the solution and detailed instructions. The solution normally contains the bpmn process model, code (Robotframework and Python) and a README that explained how the exercise was solved in more detail.

🧰 Everything needed for the workshop:

❗ Please note that the exercises build up on each other. You are always welcome to use the provided solution and continue from there. When a tool is needed for the first time it will be mentioned in the exercise again.

Exercises overview

Exercise 1: Set up a Camunda application using Docker

🏆 The goal of this exercise is to create a running Camunda instance with Docker and to inspect the examples in Cockpit

🧰 Tools needed:

Run Camunda with Docker

Camunda provides a Docker imagine. Start a Docker container of the latest Camunda Platform 7 release:

docker pull camunda/camunda-bpm-platform:latest
docker run -d --name camunda -p 8080:8080 camunda/camunda-bpm-platform:latest

📌 Note:

Once you started the container you will see the container id:

If you like to stop the container you can usedocker stop 'ContainerId' or docker stop 'Container name'


Cockpit and running process instances

Once you started the Docker container, Camunda is started in a Tomcat application server. You can access the Camunda's Frontend applications via: http://localhost:8080/camunda-welcome/index.html

Select Cockpit and log in with the default credentials:

username: demo
password: demo

Cockpit is the tool to monitor and operate running process instances in Camunda. You can see that there are already two process definitions deployed and 8 running process instances. Click on the 8 running process instances. Select the invoice process:

A running process instances is represented with a blue token:

Inspect an instance and see what information you can access. Feel free to play around in Cockpit and get familiar with it.

🎉 Congrats you have a Camunda application running and inspected the two deployed example process definitions in Cockpit

Exercise 2: Model a process and add it to your application

🏆 The goal of this exercise is to create a process and deploy it to your running Camunda application.

🧰 Tools needed:

Process Description

Imagine you start your day at Robocon: You need coffee!

Before you order your coffee you fill out a survey to find out what kind of coffee you are most like. The next step is to get all the ingrients for the defined coffee type. Once you have the ingrients you can prepare the coffee. Once your coffee is ready you want to tweet about it before you finally drink it.

Model a BPMN process model from that description in the Camunda Modeler. Hint: You can find a solution here.

Task types: user task

Once you have your process model make sure that all task types are user tasks. Change them in the Camunda Modeler.

Properties panel: technical attributes on general level

In the Camunda Modeler click into the canvas and make sure that you have not selected a bpmn symbol. Now have a look on the right side at the properties pannel. The properties panel is used to set technical attributes for symbols and the process.

Give your process a readable ID (something like: Process_getCoffee) and a readable name (something like: Get Coffee Process).

💡 Good to know:

  • The process ID is used to version your process definitions. The Camunda engine takes care about the versioning.
  • The name will show up in Cockpit. If no name is defined the processID will show up instead

Adding some UI to for the start event/ user task and using process data

There are different ways how to add forms to a user task that will be represented in Tasklist. In this workshop we are going to use Camunda forms

You can build a form using the Camunda Modeler. To do so navigate to file -> new file -> form (Camunda Platform). Now you see the Form Builder. We want to create a form for our start event. We want to know the name of the person, who wants coffee. Additionally, we want to know if the result should be tweeted or not. Maybe not everyone is a social media fan. Create a form with the two fields described. The key will create the variable name. Additionally, you can provide a readable field name and a field description. Give your form a ID too. We will need this ID to connect to your process

You can find the full form here

Now go back to your process model. In order to link the form, select the start event go to the property panel and attach your form using the form id:


📌 Note:

You can add forms to User Tasks as well. In this workshop we will replace the user tasks, so no need to build forms for it.


Using process data to route the process

We want to use the information about twitter. Just if a person selected the Twitter option we want to tweet in the end of the process. If the person did not choose twitter we will end instead. Model this logic into your process. You can find the solution here.

In order to use the data we need to add an expression after the sequence flows of the XOR gateway. Select an outgoing sequence flow and navigate in the properties' panel to condition. Choose as a type: xpression and add for the yes part: #{twitter} and for the no path: #{!twitter}

Deploy the process and your form

Now you can deploy the process Model from the Camunda Modeler to your running Camunda instance. In the left corner of the modeler you find a 🚀 symbol:

Select it:

The default REST endpoint is localhost:8080. As we started our Docker image at that port. We don't have to change it.

Use the "include additional files" option and append your form. Make sure you deploy both files!

Inspect your process in Cockpit. If you have problems with your deployment check out this section.

Run a process instance and step through the process using Tasklist

Now it is time to learn more about Tasklist. Tasklist is a Camunda Frontend application that presents a UI for a User Task. Further you can start processes from there. Go back to Cockpit in your browser.In Camunda you can navigate between the different Frontend applications using the little house symbol in the upper right corner. Open Tasklist in a new tab:

The first think we want to do is to start a process instance of our deployed model. Select the "start process"- button and choose the name of your deployed diagram:

You should see now the created form. Fill in the information and start the process.

Let's have a look on the left side of Tasklist: Tasklist

  1. You can filter tasks. In your list you can already see some predefined filters for the example process. Select the filter all tasks
  2. In this column you can see all tasks that match to the filter. You should see now the task from your "Get Coffee Process" on top. Select it
  3. This part shows the form attached to the User Task. We haven't defined any form yet. So no nothing to display here.
  4. Before a task can be completed a user has to claim the task. Claim the task
  5. Afterwards you can complete it

Do that for all tasks in your process and observe how the instance moves in Cockpit


🌟 Optional task:

  • Start a process instance using the Camunda Modeler
  • Start a process instance using Camunda's REST API
  • Use the REST API to get a task id. With the id you can claim and complete user tasks

📌 Note: For this optional task it is useful to use a tool like Postman


🎉 Congrats you have a deployed process with user tasks and a start form and stepped through it using Camunda's Tasklist

Exercise 3: Implement a Service Task: Combing the Python External Task client and Robotframework

🏆 The goal of this exercise is to connect a Robotframework Task to the process using Python and Camunda's External Task pattern.

🧰 Tools needed:

Building a Robotframework Task

We want to add some automation to our process. The first thing we would like to automate is the user-interface interaction with the coffee quiz that defines the coffee type. The Robot should random choose for each question one of the six answer posibilities.

Add one folder to your project for the Coffee Quiz Task. Within that folder create a task.robot file.In order to build the Robot we use Selenium. You can either decide to try out to build the Robotframework task yourself or use our solution from [here](/Solutions/03/Define Coffee Type Task/task.robot).

Once you have your Robotframework Task open a Terminal and type the command robot task.robot. The robot should run, and you should be able to inspect the log.html afterwards.

Change Task type to Service Task in the BPMN process

First thing we do is changing our BPMN model. Change the type of the "define coffee type" task from a user task to a service task in the Camunda Modeler:

Next we look at the property panel. We are going to implement the Service Task as External Task. Provide a topic like coffeeTypeTask.

Deploy the new version of the process and start an instance from the Modeler.

Connect a task worker to the Service Task

Next up we need an external task worker that polls the Camunda engine and fetches the task once it becomes available (a process instance waits there). We are going to use the Python 3 External Task Client. Create a new file in the "Coffee Quiz task" and name it something like worker.py. Open the file in an IDE of your choice.

import time
from camunda.external_task.external_task import ExternalTask, TaskResult
from camunda.external_task.external_task_worker import ExternalTaskWorker


def handle_task(task: ExternalTask) -> TaskResult:

   ## Your Business logic goes here

   return task.complete()

ExternalTaskWorker(worker_id="1").subscribe("coffeeTypeTask", handle_task)

This is the basic construct in order to create an external task worker in Python.

Connect robotframework task to the worker

Let's connect our robot.task to it. In Python, we can simply use the robot module and the function robot.run("task.robot"). Make sure to import the robot module in the beginning. The function returns a number. Save the number in a variable called robotOutput. If the number is 0 it means the task.robot was executed successful. We can complete the task like in the code example above.

If it contains a number bigger than 0 it means the robot task was not executed successfully. In that case we want to report to Camunda that there was a problem and add a return task.failure(error_message="RF-task failed", error_details="The RF task was not completed successfully. For more information open the log.html", max_retries=0, retry_timeout=5000). This will create an incident in the Camunda engine. This is useful for a central view of error handling and failing bots.

Add the described logic to the Python file under the Comment: "Your Business logic goes here". You can find a solution of the full code [here](/Solutions/03/Define Coffee Type Task/worker-without-robotframework-listener.py).

Now go to Cockpit. We already started an instance. You should see a second version of the process with one instances waiting at the "Define coffee type" task.

Start the Python worker in your terminal using python worker.py. Observe Cockpit. Stop the worker afterwards.


🌟 Optional task:

  • Change something in the task.robot file so the execution of the robot will fail.
  • Start a new process instance (Camunda Modeler, Tasklist or REST API)
  • Start up the worker python worker.py
  • Observe the incident showing up in Cockpit and inspect it

Getting variables from the robot task to Camunda

This is already great. We can run our robot task and communicate to Camunda if the task was successful or not. The only thing is missing is the information about the coffee type... how should the next task "get ingredients" be preformed without that information?

We can complete tasks in Camunda with handing back variables: return task.complete({"type": coffeeType}). In order to get the information from the robot task we are going to use a Robotframework listener. In the folder "Define Coffee task type" create a file called listener.py :

from robot.libraries.BuiltIn import BuiltIn

class getVariablesListener:
  ROBOT_LISTENER_API_VERSION = 2
  def end_test(self, name, attributes):
    self.variables = BuiltIn().get_variables()

  • Add the listener to your import statements at the top of the worker.py.

  • Create an object and start the robot with the listener:

l = listener.getVariablesListener()
robotOutput = robot.run("task.robot", listener=l) 

The listener gets the variables from the robot task. Afterwards we can access the variables we are interested in:

coffeeType = l.variables["${result}"]

Once you have the variable you can hand it in as parameters with the complete call to Camunda:

task.complete({"type": coffeeType})

You can find the full worker.py file with listener [here](/Solutions/03/Define Coffee Type Task/worker-with-robotframework.listener.py).

Start a new process instance of the process. If you did the optional task before make sure your robot task is error free again. Start the worker.py.

Go to Cockpit and observe the process variables from your last started instance. You should be able to see the variable type .

Getting process variables from Camunda to the task

Okay let's implement the next task following the described pattern from exercise 3. We would like to implement the Tweet about coffee task the same way. Do you remember the steps?

  • Change the Task in your BPMN Model to a service task and make it an external task with a topic
  • Create a new folder for your task Tweet about coffee task
  • Add a task.robot to connect to Twitter (using the (Twitter Keyword Library)[https://robocorp.com/docs/libraries/rpa-framework/rpa-twitter])
  • Add the worker.py to communicate with Camunda's REST API and call the task.robot in there.

If you want to connect to Twitter you need to sign up for a Twitter Developer Account. Because we want to create a Bot that tweets you need to apply for elevated access. Once you have your elevated access you can create credentials needed. In order to Send the Tweet you need the following:

  • TWITTER_CONSUMER_KEY
  • TWITTER_CONSUMER_SECRET
  • TWITTER_ACCESS_TOKEN
  • TWITTER_ACCESS_TOKEN_SECRET

If you are not sure, how to create those credentials follow the Twitter documentation.

Note: In the workshop onside we will provide the needed credentials

Store your credentials in an env.py in your Tweet about coffee task folder. The file should look like this:

#Credentials for Authorization

ENV_TWITTER_CONSUMER_KEY = "xxxxxxxxxxxxxxxxxx"
ENV_TWITTER_CONSUMER_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ENV_TWITTER_ACCESS_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ENV_TWITTER_ACCESS_TOKEN_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

We want to use the Twitter Keyword library to authorize and to send a tweet. The text we tweet should contain the name of the person that ordered the coffee and the coffee type. The task robot should look like this

In order to get the variables into the robot task we first need to store the variables from the process in a list with the following structure 'variable_name: variable_value. We can use the External Task client to access the process variables:

name = 'name: ' + task.get_variable("name")
    coffeetype = 'type: ' + task.get_variable("type")
   
    variables =[name, coffeetype]

Then we can start the task.robot from our worker.py and hand in the variable list as parameters:

 robotOutput = robot.run("task.robot", variable=variables)

You can find the full worker here.

🎉 You connected a robot task to Camunda using the Camunda Python External Task client. You used Robotframework Listener to get variables back to Camunda and created a list to hand in variables from camunda to your robot.task .

Exercise 4: Implement a Services: Using the Camunda-Robotframework library

🏆 The goal of this exercise is to connect a Robotframework task to camunda using the CamundaLibrary

Implement a task that

  • fetches a workload from Camunda
  • gets the coffee type from that workload
  • identify ingredients for your coffee by calling coffee API

Prerequisites

For this exercise you need a new dependency: robotframework-camunda

CamundaLibrary holds several keywords that are targeted to make working with Camunda REST API easier. Refer to full keyword documentation.

TL;DR

You can jump right in to the exercise now or continue reading for more background.

External Task pattern

CamundaLibrary implements an external task client for Robot Framework. Similar to original external task clients, robot tasks with CamundaLibrary follows the following sequence flow:

  1. Fetch a workload for a certain topic
  2. Finish working on a workload by
    1. complete
    2. raise an error (see exercise 5)
    3. raise an incident

Classic so called external task worker are services that subscribe to a topic and listen constantly, if workload is available.

CamundaLibrary does not provide subscription of topics. It provides keywords checking for workload on-demand. The library caches the ID of the fetched workload, so you do not have to care about which process your workload is attached to. You simply focus in processing logic. When completing working on a workload, CamundaLibrary inserts all necessary metadata required from Camunda Platform to match your results with a process instance.

That means: you can only process 1 workload at a time in 1 robot task execution. You break out from the rule und take process instance management in your own hands. CamundaLibrary will worn you though every time when you fetch a new workload without having properly completed a former one.

Exercise 5: Handling Business Errors

🏆 The goal of this exercise is to understand how to handle business errors using the BPMN error event

BPMN Errors

The modeling language BPMN offers a way to handle business errors. BPMN errors are errors that you expect to happen. Unexpected errors are considered incidents. We already covered incidents in exercise 3

In order to model a bpmn error we can attach a boundary event to a task. You can drag and drop an intermediate event from the left side panel from the modeler and place it on a task. Attach Boundary Event

Then you can change the type to an error event and define the alternative path once a task is interrupted.

Change to BPMN Error Event For our process we want a user to add the ingredients for a certain coffee type if the coffee API can't find it. If Twitter raises a tweet duplication error we want that a user has the chance to adjust the tweet.

Include that logic into your process diagram. You can find the solution here

Next we will see how we can throw the BPMN error in our code

With Python External Task Client

First let's fill in the details in the properties' panel in the Camunda Modeler. Select the BPMN Error boundary event and create a new global error reference.

Fill in the other details.

We already know that the external Task client can complete and fail a service task. A third method is to throw a bpmn error.

return task.bpmn_error(error_code="err_duplicate", error_message="The Tweet is a duplicate")

The error_code needs to match with the error code in the Model. In fact the Twitter API gives us a duplication error if we try to send the same tweet within 24 hours. If we get the duplication error we don't want to fail the task, but instead return a BPMN error so a user has the chance to adjust the tweet.

Try to access the Robotframework task error message and implement the logic in the worker.py for the Send Tweet task.

With Camunda-Robotframework library

For raising a BPMN error with CamundaLibrary, you use the keyword Throw BPMN Error (keyword documentation here).