Creating your first workflow service
As a developer, you can use Serverless Workflow and create a Hello World
application, which includes the following procedures:
Also, you can directly access an example application by cloning serverless-workflow-examples/serverless-workflow-hello-world
from the GitHub repository.
This document describes how to create a workflow application that serves a hello_world
endpoint. The workflow contains the following two states:
-
Inject Hello World
: Injects aHello World
message into the response -
Inject Mantra
: Injects aMantra
message into the response
-
Java 11+ is installed with
JAVA_HOME
configured appropriately. -
Apache Maven 3.8.1 is installed.
-
Quarkus CLI or Knative Workflow CLI 0.21.2 is installed.
-
Visual Studio Code with Red Hat Java Extension and Red Hat Serverless Workflow Editor is installed to edit your workflows.
For more information about the tooling and the required dependencies, see Getting familiar with Serverless Workflow tooling.
Bootstrapping a project
To create your workflow service, first you need to bootstrap a project.
-
In a command terminal, use one of the following commands to create a project:
Create a project using Quarkus CLIquarkus create app \ -x=kogito-quarkus-serverless-workflow \ -x=quarkus-container-image-jib \ -x=quarkus-resteasy-jackson \ -x=quarkus-smallrye-openapi \ --no-code \ org.kie.kogito.examples:serverless-workflow-hello-world:1.0
The previous command creates a Maven Quarkus project in the
serverless-workflow-hello-world
directory containing the required dependencies, including:-
kogito-quarkus-serverless-workflow
: Adds support for workflows. -
quarkus-container-image-jib
: Adds support for Container Image Builds. -
quarkus-resteasy-jackson
: Adds support for RESTEasy, which is required by the generated REST resources that are used to start the flow process using an HTTP request. -
quarkus-smallrye-openapi
: Adds support for Swagger documentation when you run the application in development mode. -
--no-code
: Prevents workflow example code from being generated.
The SwaggerUI is available at
http://localhost:8080/q/swagger-ui/
when you run the application.Create a project using Apache Mavenmvn io.quarkus.platform:quarkus-maven-plugin:2.10.2.Final:create \ -DprojectGroupId=org.kie.kogito.examples \ -DprojectArtifactId=serverless-workflow-hello-world \ -Dextensions="kogito-quarkus-serverless-workflow,quarkus-container-image-jib,quarkus-resteasy-jackson,quarkus-smallrye-openapi" \ -DnoCode cd serverless-workflow-hello-world
In the previous command,
org.kie.kogito.examples
,serverless-workflow-hello-world
, and1.0
is group ID, artifact ID, and version of your project respectively.-DnoCode
prevents the generation of workflow example code.Create a project using Knative CLIkn workflow create \ --name serverless-workflow-hello-world \ --extension quarkus-jsonp,quarkus-smallrye-openapi \ --quarkus-platform-group-id=io.quarkus.platform \ --quarkus-version=2.10.2.Final
For more information about Knative CLI, see Serverless Workflow plug-in for Knative CLI.
-
Creating a workflow
After bootstrapping a project, you need to create a workflow. In the following procedure, a workflow named Hello World Workflow is created.
-
Create a file named
hello.sw.json
in thesrc/main/resources
directory with the following content:Example content forhello.sw.json
file{ "id": "hello_world", (1) "version": "1.0", "specVersion": "0.8", "name": "Hello World Workflow", "description": "JSON based hello world workflow", "start": "Inject Hello World", (3) "states": [ (2) { "name": "Inject Hello World", "type": "inject", (4) "data": { (5) "greeting": "Hello World" }, "transition": "Inject Mantra" (6) }, { "name": "Inject Mantra", "type": "inject", "data": { "mantra": "Serverless Workflow is awesome!" (7) }, "end": true (8) } ] }
In the previous example:
1 id
field is the unique identifier of the workflow. Kogito generates the REST endpoints based on this unique identifier.2 states
defines the states of the workflow. In the Hello World example, the workflow contains two states, such asInject Hello World
andInject Mantra
.3 start
field defines the state in which the workflow starts.4 type
defines the type of the state. In the previous example, the state isinject
. Theinject
state can be used to inject static data into state data input.5 data
defines the data that is injected into the state. In the previous example,greeting
is injected with theHello World
value.6 transition
field defines the next state that is reached after the current state is completed.7 Injects a mantra
with the valueServerless Workflow is awesome!
into the workflow data.8 end
field defines that the current state is the end of the workflow. When the workflow reaches the end state, the workflow stops and the REST endpoint returns the workflow data, such as:Example workflow data{ "greeting": "Hello World", "mantra": "Serverless Workflow is awesome!" }
The workflow definition follows the CNCF Serverless Workflow specification. For more information, see CNCF Serverless Workflow specification.
Building your workflow application
-
To verify that project is created, compile the project using the following command:
Compile your project using Quarkus CLIquarkus build
Compile your project using Apache Mavenmvn clean package
Build your project and generate a local image calleddev.local/serverless-workflow-hello-world:latest
kn workflow build --image dev.local/serverless-workflow-hello-world --verbose
The
--verbose
flag is used to display the output of the build command. This flag is optional.For more information about Knative CLI, see Serverless Workflow plug-in for Knative CLI.
After building the image, add
imagePullPolicy: IfNotPresent
to thetarget/kubernetes/knative.yml
file. Your file should look similar to:Exampletarget/kubernetes/knative.yml
file--- apiVersion: serving.knative.dev/v1 kind: Service metadata: annotations: app.quarkus.io/build-timestamp: 2022-08-09 - 21:26:59 +0000 labels: app.kubernetes.io/version: latest app.kubernetes.io/name: serverless-workflow-hello-world name: serverless-workflow-hello-world spec: template: metadata: labels: app.kubernetes.io/version: latest app.kubernetes.io/name: serverless-workflow-hello-world spec: containerConcurrency: 0 containers: - image: dev.local/serverless-workflow-hello-world:latest imagePullPolicy: IfNotPresent (1) name: serverless-workflow-hello-world ports: - containerPort: 8080 name: http1 protocol: TCP
1 imagePullPolicy
field defines the policy for pulling the image from the registry.
Running your workflow application
After creating a workflow, you can run your workflow application.
-
Enter the following command to run your workflow application:
Run your workflow application using Quarkus CLIquarkus dev
Run your workflow application using Apache Mavenmvn clean quarkus:dev
Deploy your project to authenticated clusterkn workflow deploy
For more information about Knative CLI, see Serverless Workflow plug-in for Knative CLI.
Example response[INFO] ------< org.kie.kogito.examples:serverless-workflow-hello-world >------- [INFO] Building serverless-workflow-hello-world 1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- quarkus-maven-plugin:2.10.2.Final:dev (default-cli) @ serverless-workflow-hello-world --- [INFO] Invoking org.apache.maven.plugins:maven-resources-plugin:2.6:resources) @ serverless-workflow-hello-world [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 3 resources ...more output... __ ____ __ _____ ___ __ ____ ______ --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ --\___\_\____/_/ |_/_/|_/_/|_|\____/___/ 2022-05-25 14:38:09,741 INFO [org.kie.kog.add.qua.mes.com.QuarkusKogitoExtensionInitializer] (Quarkus Main Thread) Registered Kogito CloudEvent extension 2022-05-25 14:38:09,840 INFO [io.quarkus] (Quarkus Main Thread) serverless-workflow-hello-world 1.0 on JVM (powered by Quarkus 2.10.2.Final) started in 6.470s. Listening on: http://localhost:8080 2022-05-25 14:38:09,843 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. 2022-05-25 14:38:09,843 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cache, cdi, jackson-jq, kogito-addon-messaging-extension, kogito-processes, kogito-serverless-workflow, reactive-routes, rest-client, rest-client-jackson, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-openapi, smallrye-reactive-messaging, smallrye-reactive-messaging-http, swagger-ui, vertx] 2022-05-25 14:38:12,877 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: __ ____ __ _____ ___ __ ____ ______ 2022-05-25 14:38:12,878 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 2022-05-25 14:38:12,879 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ 2022-05-25 14:38:12,879 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: --\___\_\____/_/ |_/_/|_/_/|_|\____/___/ 2022-05-25 14:38:12,879 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:09,692 INFO [io.zon.tes.db.pos.emb.EmbeddedPostgres] (main) Detected a Linux x86_64 system 2022-05-25 14:38:12,880 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:09,705 INFO [io.zon.tes.db.pos.emb.DefaultPostgresBinaryResolver] (main) Detected distribution: 'Red Hat Enterprise Linux' ...more output... 2022-05-25 14:38:12,889 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:12,332 INFO [io.zon.tes.db.pos.emb.EmbeddedPostgres] (postgres:pid(90)) 2022-05-25 17:38:12.332 UTC [99] LOG: incomplete startup packet 2022-05-25 14:38:12,890 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:12,405 INFO [io.zon.tes.db.pos.emb.EmbeddedPostgres] (main) 5df1ed6e-7a15-4091-bcfb-e293aa293bfe postmaster startup finished in 00:00:00.180 2022-05-25 14:38:12,890 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:12,405 INFO [org.kie.kog.per.inm.pos.run.InmemoryPostgreSQLRecorder] (main) Embedded Postgres started at port "44729" with database "postgres", user "postgres" and password "postgres" 2022-05-25 14:38:12,890 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:12,636 WARN [io.qua.run.con.ConfigRecorder] (main) Build time property cannot be changed at runtime: 2022-05-25 14:38:12,891 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: - quarkus.jib.base-jvm-image is set to 'ba-docker-registry.usersys.redhat.com:5000/fabric8/java-alpine-openjdk11-jre' but it is build time fixed to 'fabric8/java-alpine-openjdk11-jre'. Did you change the property quarkus.jib.base-jvm-image after building the application? 2022-05-25 14:38:13,375 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:13,105 INFO [org.kie.kog.per.pro.ProtobufService] (main) Registering Kogito ProtoBuffer file: kogito-index.proto 2022-05-25 14:38:13,377 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:13,132 INFO [org.kie.kog.per.pro.ProtobufService] (main) Registering Kogito ProtoBuffer file: kogito-types.proto 2022-05-25 14:38:13,378 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:13,181 INFO [io.quarkus] (main) data-index-service-inmemory 1.22.0.Final on JVM (powered by Quarkus 2.9.0.Final) started in 4.691s. Listening on: http://0.0.0.0:8080 2022-05-25 14:38:13,379 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:13,182 INFO [io.quarkus] (main) Profile prod activated. 2022-05-25 14:38:13,380 INFO [org.kie.kog.qua.pro.dev.DataIndexInMemoryContainer] (docker-java-stream--938264210) STDOUT: 2022-05-25 17:38:13,182 INFO [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, inmemory-postgres, jdbc-postgresql, narayana-jta, oidc, reactive-routes, rest-client-reactive, rest-client-reactive-jackson, security, smallrye-context-propagation, smallrye-graphql-client, smallrye-health, smallrye-metrics, smallrye-reactive-messaging, smallrye-reactive-messaging-http, vertx, vertx-graphql]
Example response✅ Knative service sucessufully created 🚀 Deploy took: 194.263309ms
Verify Knative servicekn service list
Example responseNAME URL LATEST AGE CONDITIONS READY REASON serverless-workflow-hello-world http://serverless-workflow-hello-world.default.10.106.207.219.sslip.io serverless-workflow-hello-world-00001 6s 3 OK / 3 True
The returned URL must be used to access the deployed service.
-
Once your workflow application is started, you can send a request for the provided endpoint:
Example requestcurl -X POST -H 'Content-Type:application/json' http://localhost:8080/hello_world
Use the URL returned by the previous command to access the deployed service:
Example requestURL=$(kn service describe serverless-workflow-hello-world -o url) curl -X POST -H 'Content-Type:application/json' ${URL}/hello_world
Example response{"id":"efb59bfa-ad9c-4062-a6d2-2d9184dd4b3d","workflowdata":{"greeting":"Hello World","mantra":"Serverless Workflow is awesome!"}}
-
When running in development mode (using Quarkus CLI or Apache Maven), you can update your workflow with a new
mantra
value without restarting the application.Update your workflow{ "name": "Inject Mantra", "type": "inject", "data": { "mantra": "Serverless Workflow is amazing!" (1) }, "end": true }
1 New mantra
valueExample requestcurl -X POST -H 'Content-Type:application/json' http://localhost:8080/hello_world
Example response{"id":"efb59bfa-ad9c-4062-a6d2-2d9184dd4b3d","workflowdata":{"greeting":"Hello World","mantra":"Serverless Workflow is amazing!"}}
Note that the
mantra
value is updated without restarting the application, because Kogito leverages the Quarkus live coding feature. -
To stop the application, press
CTRL+C
.
Testing your workflow application
To test your workflow application, you can follow the instructions in the Testing your workflow application using REST Assured.
Found an issue?
If you find an issue or any misleading information, please feel free to report it here. We really appreciate it!