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 a Hello World message into the response

  • Inject Mantra: Injects a Mantra message into the response

hello world workflow
Figure 1. Example Hello World workflow
Prerequisites

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.

Procedure
  1. In a command terminal, use one of the following commands to create a project:

    • Quarkus CLI

    • Apache Maven

    • Knative CLI

    Create a project using Quarkus CLI
    quarkus 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 Maven
    mvn 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, and 1.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 CLI
    kn 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.

Procedure
  1. Create a file named hello.sw.json in the src/main/resources directory with the following content:

    Example content for hello.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 as Inject Hello World and Inject 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 is inject. The inject 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 the Hello World value.
    6 transition field defines the next state that is reached after the current state is completed.
    7 Injects a mantra with the value Serverless 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

  1. To verify that project is created, compile the project using the following command:

    • Quarkus CLI

    • Apache Maven

    • Knative CLI

    Compile your project using Quarkus CLI
    quarkus build
    Compile your project using Apache Maven
    mvn clean package
    Build your project and generate a local image called dev.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 the target/kubernetes/knative.yml file. Your file should look similar to:

    Example target/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.

Procedure
  1. Enter the following command to run your workflow application:

    • Quarkus CLI

    • Apache Maven

    • Knative CLI

    Run your workflow application using Quarkus CLI
    quarkus dev
    Run your workflow application using Apache Maven
    mvn clean quarkus:dev
    Deploy your project to authenticated cluster
    kn workflow deploy

    For more information about Knative CLI, see Serverless Workflow plug-in for Knative CLI.

    • Quarkus CLI or Apache Maven

    • 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 service
    kn service list
    Example response
    NAME                              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.

  2. Once your workflow application is started, you can send a request for the provided endpoint:

    • Quarkus CLI or Apache Maven

    • Knative CLI

    Example request
    curl -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 request
    URL=$(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!"}}
  3. 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 value
    Example request
    curl -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.

  4. 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!