Skip to main content

Send an email - Temporal.io based Worker

This tutorial in a nutshell

With this guide we will build a simple Temporal-based Worker in Java language that will show the key aspects of a KuFlow integration. Our example will model a Workflow whose purpose is to send an email using the information that a user completes within a task in the application.

Together with the construction of the worker, it is necessary to register it in KuFlow and configure the permissions that you consider appropriate. In this tutorial we will focus on the implementation of the Worker and we will name in a schematic way the necessary configurations to be made by the user in the application.

Prerequisites

Before starting our Worker for the first time, we must register it in KuFlow (app.kuflow.com). After familiarizing yourself with the user interface, you are ready to perform the necessary configurations for our Worker. To do so, click on the Settings menu. If you do not see this menu, you probably do not have the necessary permissions to define processes, so you will have to request it from your Organization administrators, or simply create a FREE new account.

Create the credentials for the Worker

We will configure an APPLICATION that will provide us with the necessary credentials so that different external systems can interface with KuFlow, in this example, the necessary credentials for our Worker.

Go to the Settings > Applications menu and click on Add application. We establish the name we want and save. Next, you will get the first data needed to configure our Worker.

  • Identifier: Unique identifier of the application.
    • Later in this tutorial, we will configure it in the kuflow.api.client-id property of our example.
  • Token: Password for the application.
    • Later in this tutorial, we will configure it in the kuflow.api.client-secret property of our example.

Finally, you get something like:

Create the process definition

We need to create the definition of the process that will execute our Workflow. In this section we will configure the KuFlow tasks of which it is made up as well as the information necessary to complete said tasks, the process access rules (i.e. RBAC), as well as another series of information. To do this we go to the Setting > Processes menu and create a new process.

A Process Definition with the following data:

  • Description
    • Free text description about the Workflow.
  • Workflow
    • Workflow Engine
      • KuFlow Engine, because we are designing a Temporal-based Worker.
    • Workflow Application
      • The application to which our Worker will connect to
    • Task queue
      • The name of the Temporal queue where the KuFlow tasks will be set. You can choose any name, later you will set this same name in the appropriate configuration in your Worker. For example: ExampleQueue.
    • Name
      • It must match the name of the Java interface of the Workflow. In our example, SampleWorkflow is the name you should type in this input.
  • Permissions
    1. At least one user or group of users with the role of INITIATOR in order to instantiate the process through the application.
      1. Optional: In order to view administrative actions in the GUI, it may interesting to set the Manager role as well for some user.

Finally, you get something like:

Two Tasks Definitions in the process with the following data:

  • Task "Mail Info"
    • Description: Free text description about the Task.
    • Code: FILL_INFO
    • Candidates:
      • At least one possible user or group of users who will be in charge of completing the task.
    • Element to fill the email:
      • Name: Field's label, for example "Recipient"
      • Code: EMAIL_RECIPIENT
      • Type: Field
      • Properties: Mandatory, remaining unchecked.
      • Field Type: Text
    • Element to fill email subject:
      • Name: Field's label, for example "Subject"
      • Code: EMAIL_SUBJECT
      • Type: Field
      • Properties: Mandatory, remaining unchecked.
      • Field Type: Text
    • Element to fill email subject:
      • Name: Field's label, for example "Body"
      • Code: EMAIL_BODY
      • Type: Field
      • Properties: Mandatory remaining unchecked.
      • Field Type: Text
        • Properties: Multiline

  • Task "Send email"
    • Description: Free text description about the Task.
    • Code: SEND_EMAIL
    • Candidates:
      • Set the application that represents our worker.

Source code for our Worker

Source Code

The source code for this example can be obtained from our java examples repository

danger

You can always inspect the source code in our repository, however, an alternative methodology could be to download the example template code for the process we are going to implement and compare it with the complete example in our repository. To download the initial template you must access the workflow definition in the App, and once configured, use the download template option.

Main technologies used in the example

The source code of this tutorial is available in our GitHub so you can clone it or directly download the zip.

  • Java JDK

    • You need to have a Java JDK installed on your system. The current example code uses version 17, but is not required for the KuFlow SDK. You can use for example Adoptium distribution or any other. We recommend you to use the tool like SDKMan to install Java SDK distributions in a comfortable way.
  • Maven

    • To build the example. It is distributed in an integrated way so it is not necessary to install it in isolation.
  • Spring Boot and Spring Cloud

    • To wire all our integrations.
  • Thymeleaf

    • As a template engine for our email.
  • IDE

  • An IDE with good Java support is necessary to work comfortably. You can use VSCode, IntelliJ Idea, Eclipse or any other with corresponding Java plugins.

  • Docker and Compose

  • In this example we will use Docker to create a container with a small SMTP test server. If you prefer, you can skip this step and use directly the configuration of an email server such as Gmail or any other.

To make things simpler, the following dependencies have been used in our example:

  • KuFlow Java SDK
    • Provide some activities and utilities to work with KuFlow.
  • Temporal Java SDK
    • To perform GRPC communications with the KuFlow temporal service.

Implementation details

The workflow

The entry point to the Workflow execution is determined by the @WorkflowMethod annotation, in our code the main method would be the following:

SampleWorkflowImpl.java

@Override
public WorkflowResponse runWorkflow(WorkflowRequest workflowRequest) {
this.kuflowGenerator = new KuFlowGenerator(workflowRequest.getProcessId());

UUID processId = workflowRequest.getProcessId();

Task taskFillInfo = this.createTaskFillInfo(processId);

this.createAutomaticTaskSendEmail(processId, taskFillInfo);

return this.completeWorkflow(workflowRequest);
}

The structure is very simple:

  1. Create a KuFlow Task to complete the information required to send the email.
  2. Create a KuFlow Task to perform the email delivery
  3. Report completed Workflow.

Each of these blocks, executes one or more Temporal activities that perform the necessary logic. For example, let's focus on the Workflow function createAutomaticTaskSendEmail. Its implementation uses several activities:

  1. Create task
  2. Claim the task
  3. Send an email from data that is collected from a previous task
  4. Add feedback to the automatic task for display in the KuFlow app
  5. Complete the task
private void createAutomaticTaskSendEmail(UUID processId, Task infoTask) {
UUID taskId = this.kuflowGenerator.randomUUID();

TaskDefinitionSummary tasksDefinition = new TaskDefinitionSummary();
tasksDefinition.setCode(TaskDefinitionCode.SEND_EMAIL.name());

Task task = new Task();
task.setId(taskId);
task.setProcessId(processId);
task.setTaskDefinition(tasksDefinition);

// Create Automatic Task in KuFlow
this.createTaskAndWaitCompleted(task);

// Claim Automatic Task: Our worker will be responsible for its completion.
ClaimTaskRequest claimTaskRequest = new ClaimTaskRequest();
claimTaskRequest.setTaskId(taskId);
this.kuFlowActivities.claimTask(claimTaskRequest);

// Get values from Info Task
Email email = new Email();
email.setTemplate("email");
email.setTo(TaskUtils.getElementValueAsString(infoTask, ElementDefinitionCode.EMAIL_RECIPIENT.name()));
email.addVariables("subject", TaskUtils.getElementValueAsString(infoTask, ElementDefinitionCode.EMAIL_SUBJECT.name()));
email.addVariables("body", TaskUtils.getElementValueAsString(infoTask, ElementDefinitionCode.EMAIL_BODY.name()));

// Add some logs to Kuflow task in order to see feedback in Kuflow app
this.addLogInfoEntryTask(taskId, "Sending email to " + email.getTo());

// Send a mail
SendMailRequest request = new SendMailRequest();
request.setEmail(email);
this.emailActivities.sendMail(request);

// Add some logs to Kuflow task in order to see feedback in Kuflow app
this.addLogInfoEntryTask(taskId, "Email sent!");

// Activity Complete
CompleteTaskRequest completeRequest = new CompleteTaskRequest();
completeRequest.setTaskId(taskId);
this.kuFlowActivities.completeTask(completeRequest);
}

The worker

We will use two facades of activities from our component catalog to implement the activities that perform the communication with the KuFlow REST API and the email sending activities. These activities along with the implemented Workflow, we register them in the Temporal bootstrap class.

TemporalBootstrap.java

private void startWorkers() {
this.kuFlowTemporalConnection.configureWorker(builder ->
builder
.withTaskQueue(this.sampleEngineWorkerEmailProperties.getTemporal().getKuflowQueue())
.withWorkflowImplementationTypes(SampleWorkflowImpl.class)
.withActivitiesImplementations(this.kuFlowActivities)
.withActivitiesImplementations(this.emailActivities)
);

this.kuFlowTemporalConnection.start();
}

Worker configuration

The last step of this section is filling up the application configuration information. You must complete all the settings and replace the example values. The appropriate values can be obtained from the KuFlow application. Check out the Create the credentials for the Worker section of this tutorial.

# ===================================================================
# PLEASE COMPLETE ALL CONFIGURATIONS BEFORE STARTING THE WORKER
# ===================================================================
kuflow:
api:
# ID of the APPLICATION configured in KUFLOW.
# Get it in "Application details" in the Kuflow APP.
client-id: FILL_ME

# TOKEN of the APPLICATION configured in KUFLOW.
# Get it in "Application details" in the Kuflow APP.
client-secret: FILL_ME

temporal:
# Temporal Queue. Configure it in the "Process definition" in the KUFLOW APP.
kuflow-queue: "ExampleQueue"

Please note that this is a YAML, respect the indentation.

We can test this scenario, initiating the process several times, in order to create different applications and approvals

Others configurations

The rest of the mandatory settings have been filled in for you in the application.yml file. You don't have to edit them unless you need to customize some settings, for example the SMTP server used to send our test email.

If you want to use the FakeSMTP server configured via the supplied docker-compose file, you won't have to modify anything else in this file. If instead you want to use another SMTP server, you must edit or add the appropriate keys. You can refer to the Spring Boot reference for this or take a look at the MailProperties.

spring:
mail:
host: 127.0.0.1
port: 3025
username: username
password: password
test-connection: true

Mail template

In the same file application.yaml you must configure the access to the SMTP server to send emails. If you want to use the FakeSMTP server configured via the sample you don't need to do more.

We use Thymeleaf to generate an HTML template to send the email using this format. The component that implements the email activity is conveniently configured and therefore all we have to do is create a template and place it in the path src/main/resources/templates. In this example we have created the email.html template for the body and the email.subject template for the email subject

Run

First you must start the docker compose that we supply if you use the included SMTP test server.

# In path: kuflow-components-java/kuflow-worker-sample
docker compose up

Next, you must start the Worker. Normally, you will do this through the IDE. But if you prefer the console line, in the repository root folder type:

./mvnw spring-boot:run -f kuflow-engine-samples-worker-email/pom.xml

If the Worker starts successfully, you will see the following log output.

----------------------------------------------------------
Application 'KuFlow Engine Worker Sample Email' is running! Access URLs:
Local: http://localhost:null/
External: http://127.0.1.1:null/
Profile(s): [dev]
----------------------------------------------------------

When a connected Worker that implements our example process is registered, in the application we can see how the badge associated with the Workflow Engine field changes from Disconnected to Connected. Finally, users with the appropriate permissions will be able to run a Process that executes the Workflow we have just implemented. To do this, from the non-administrative part of the KuFlow application, we instantiate the process by clicking on the "Start process" button.

Once you have completed all the steps the Workflow will be completed and the email will be sent. You can check this in the FakeSMTP web interface: http://localhost:8082/

Summary

In this tutorial we have shown a practical use case of an activity for sending emails whose implementation is available in the KuFlow open source repositories.

Kuflow Logo