blob: 64db8ed919e4ddaa7d11725f3fbf19d07b499a66 [file] [log] [blame]
= Creating your first workflow service
As a developer, you can use {context} and create a `Hello World` application, which includes the following procedures:
* <<proc-boostrapping-the-project,Bootstrapping a project>>
* <<proc-creating-workflow,Creating a workflow>>
* <<proc-running-application,Running your workflow application>>
* <<proc-testing-application,Testing your workflow application>>
Also, you can directly access an example application by cloning `serverless-workflow-examples/serverless-workflow-hello-world` from the link:{kogito_sw_examples_url}/serverless-workflow-hello-world[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
.Example Hello World workflow
image::getting-started/hello-world-workflow.png[]
.Prerequisites
* Java {java_min_version} is installed with `JAVA_HOME` configured appropriately.
* Apache Maven {maven_min_version} is installed.
* {quarkus_cli_url}[Quarkus CLI] or xref:tooling/kn-plugin-workflow-overview.adoc[Knative Workflow CLI] {kn-cli-version} is installed.
* Visual Studio Code with https://marketplace.visualstudio.com/items?itemName=redhat.java[Red Hat Java Extension]
and https://marketplace.visualstudio.com/items?itemName=redhat.vscode-extension-serverless-workflow-editor[Red Hat Serverless Workflow Editor] is installed to edit your workflows.
For more information about the tooling and the required dependencies, see xref:getting-started/getting-familiar-with-our-tooling.adoc[Getting familiar with {context} tooling].
ifeval::["{kogito_version_redhat}" != ""]
include::../../pages/_common-content/downstream-project-setup-instructions.adoc[]
endif::[]
[[proc-boostrapping-the-project]]
== Bootstrapping a project
To create your workflow service, first you need to bootstrap a project.
.Procedure
. In a command terminal, use one of the following commands to create a project:
+
[tabs]
====
Quarkus CLI::
+
--
.Create a project using Quarkus CLI
[source,shell,subs="attributes+"]
----
quarkus create app \
-x={kogito_sw_ga} \
-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_sw_ga}`: 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.
--
Apache Maven::
+
--
.Create a project using Apache Maven
[source,shell,subs="attributes"]
----
mvn {quarkus_platform}:quarkus-maven-plugin:{quarkus_version}:create \
-DprojectGroupId=org.kie.kogito.examples \
-DprojectArtifactId=serverless-workflow-hello-world \
-Dextensions="{kogito_sw_ga},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.
--
Knative CLI::
+
--
.Create a project using Knative CLI
[source,shell,subs="attributes"]
----
kn workflow create \
--name serverless-workflow-hello-world \
--extension quarkus-jsonp,quarkus-smallrye-openapi \
--quarkus-platform-group-id={quarkus_platform} \
--quarkus-version={quarkus_version}
----
For more information about Knative CLI, see xref:tooling/kn-plugin-workflow-overview.adoc[{context} plug-in for Knative CLI].
--
====
[[proc-creating-workflow]]
== 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
. Create a file named `hello.sw.json` in the `src/main/resources` directory with the following content:
+
--
.Example content for `hello.sw.json` file
[source,json]
----
{
"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. {product_name} 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
[source,json]
----
{
"greeting": "Hello World",
"mantra": "Serverless Workflow is awesome!"
}
----
[NOTE]
====
The workflow definition follows the CNCF Serverless Workflow specification. For more information, see
xref:getting-started/cncf-serverless-workflow-specification-support.adoc[CNCF Serverless Workflow specification].
====
--
[[proc-building-application]]
== Building your workflow application
ifeval::["{kogito_version_redhat}" != ""]
include::../../pages/_common-content/downstream-post-create-project.adoc[]
endif::[]
. To verify that project is created, compile the project using the following command:
+
[tabs]
====
Quarkus CLI::
+
--
.Compile your project using Quarkus CLI
[source,shell]
----
quarkus build
----
--
Apache Maven::
+
--
.Compile your project using Apache Maven
[source,shell]
----
mvn clean package
----
--
Knative CLI::
+
--
.Build your project and generate a local image called `dev.local/serverless-workflow-hello-world:latest`
[source,shell]
----
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 xref:tooling/kn-plugin-workflow-overview.adoc[{context} 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
[source,yaml]
----
---
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.
--
====
[[proc-running-application]]
== Running your workflow application
After creating a workflow, you can run your workflow application.
.Procedure
. Enter the following command to run your workflow application:
+
[tabs]
====
Quarkus CLI::
+
--
.Run your workflow application using Quarkus CLI
[source,shell]
----
quarkus dev
----
--
Apache Maven::
+
--
.Run your workflow application using Apache Maven
[source,shell]
----
mvn clean quarkus:dev
----
--
Knative CLI::
+
--
.Deploy your project to authenticated cluster
[source,shell]
----
kn workflow deploy
----
For more information about Knative CLI, see xref:tooling/kn-plugin-workflow-overview.adoc[{context} plug-in for Knative CLI].
--
====
+
[tabs]
====
Quarkus CLI or Apache Maven::
+
.Example response
[source,shell,subs="attributes"]
----
[INFO] ------< org.kie.kogito.examples:serverless-workflow-hello-world >-------
[INFO] Building serverless-workflow-hello-world 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- quarkus-maven-plugin:{quarkus_version}: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 {quarkus_version}) 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]
----
Knative CLI::
+
.Example response
[source,shell]
----
Knative service sucessufully created
🚀 Deploy took: 194.263309ms
----
+
.Verify Knative service
[source,shell]
----
kn service list
----
+
.Example response
[source,shell]
----
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.
====
. Once your workflow application is started, you can send a request for the provided endpoint:
+
[tabs]
====
Quarkus CLI or Apache Maven::
+
--
.Example request
[source,shell]
----
curl -X POST -H 'Content-Type:application/json' http://localhost:8080/hello_world
----
--
Knative CLI::
+
--
Use the URL returned by the previous command to access the deployed service:
.Example request
[source,shell]
----
URL=$(kn service describe serverless-workflow-hello-world -o url)
curl -X POST -H 'Content-Type:application/json' ${URL}/hello_world
----
--
====
+
--
.Example response
[source,shell]
----
{"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
[source,json]
----
{
"name": "Inject Mantra",
"type": "inject",
"data": {
"mantra": "Serverless Workflow is amazing!" <1>
},
"end": true
}
----
<1> New `mantra` value
.Example request
[source,shell]
----
curl -X POST -H 'Content-Type:application/json' http://localhost:8080/hello_world
----
.Example response
[source,shell]
----
{"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 {product_name} leverages the Quarkus live coding feature.
--
. To stop the application, press `CTRL+C`.
[[proc-testing-application]]
== Testing your workflow application
To test your workflow application, you can follow the instructions in the
xref:testing-and-troubleshooting/basic-integration-tests-with-restassured.adoc[Testing your workflow application using REST Assured].
== Additional resources
* xref:getting-started/getting-familiar-with-our-tooling.adoc[Getting familiar with {context} tooling]
* xref:service-orchestration/orchestration-of-openapi-based-services.adoc[Orchestrating the OpenAPI services]
include::../../pages/_common-content/report-issue.adoc[]