diff --git a/serverless-operator-examples/serverless-workflow-inventory/README.md b/serverless-operator-examples/serverless-workflow-inventory/README.md new file mode 100644 index 0000000000..f932b1431a --- /dev/null +++ b/serverless-operator-examples/serverless-workflow-inventory/README.md @@ -0,0 +1,60 @@ +# Serverless Operator - Inventory Example + +## Description + +This example is meant to let you understand ho to deploy on Kubernetes the [Inventory Logic Tutorial](https://redhat-scholars.github.io/serverless-workflow/osl/index.html) using the [Operator](https://github.com/kiegroup/kogito-serverless-operator). +We will report here for this reason only a short summary about the workflow use case, and we kindly suggest you to read the full documentation about this tutorial if you need more details about it. + +### Use Case + +An e-commerce company has to implement the following **order management** workflow: + +* When a new order come in, they need to **check the inventory** for the availability of the items. If the items are available the order will be **prepared for shipping** (picking, packaging, printing label, etc), when the shipping is completed, the shipping department send an event back to the workflow and the customer is **notified** about the shipping status with usual tracking information. +* If the item is out of stock, the order will be forwarded to an **external supplier** who will take care of the shipping procedure, when the **supplier ships** the order, it also send an event back to the workflow, in such a way the workflow can continue and **send the notification** to the customer. +* As long as the order is not shipped, the customer has the option of **cancelling the order** by also cancelling the shipping. + +The following picture shows a high level design: + +![Inventory Workflow](order.svg "Inventory Workflow") + +## Deploy the Inventory workflow on Kubernetes + +### Prepare your environment + +1. Install [minikube](https://minikube.sigs.k8s.io/docs/start/) +2. Install the [Operator](https://kiegroup.github.io/kogito-docs/serverlessworkflow/latest/cloud/operator/install-serverless-operator.html) + +### Deploy the Workflow with Quarkus in Dev Mode +In the [resources](./resources/) directory you can find the Kubernete CustomResources that you need in order to deploy this workflow on your cluster in dev mode. + +To do this you only need to apply these resources using the following commands: + +```bash +kubectl create namespace my-workflows +kubectl apply -f ./resources/ -n my-workflows +``` + +### Test that the workflow is running + +Open a new terminal and start the flow with the following command: + +```shell +#!/bin/sh +ADDRESS=$(kubectl get SonataFlow -n my-workflows -o custom-columns="URL":.status.address.url --no-headers) +curl -X POST $ADDRESS \ + -H 'Content-Type:application/json' -H 'Accept:application/json' \ + -d '{ "workflowdata": { "orderId": "order-123"} }' +``` + +You should get back the output which resembles the following: + +```shell +{"id":"7484e05f-3b95-4ac7-8c09-a2c717a0293e","workflowdata":{"orderId":"order-123"}} +``` + +In the other terminal where Quarkus is running you can spot the following message in log: +```shell +Order received: order-123 +``` + +**CONGRATULATION!!!** Your first Serverless Workflow was executed as expected! diff --git a/serverless-operator-examples/serverless-workflow-inventory/order.svg b/serverless-operator-examples/serverless-workflow-inventory/order.svg new file mode 100644 index 0000000000..6549e4923c --- /dev/null +++ b/serverless-operator-examples/serverless-workflow-inventory/order.svg @@ -0,0 +1 @@ + Start Order ReceivedCheck InventoryItem Available?Prepare for Shipping Forward to External Supplier Order Shipped or Cancelled Is Shipped?Compensate Order End Notify Customer End order cance... order cance... .inventory .inventory \ No newline at end of file diff --git a/serverless-operator-examples/serverless-workflow-inventory/resources/01-configmap_01-order-resources.yaml b/serverless-operator-examples/serverless-workflow-inventory/resources/01-configmap_01-order-resources.yaml new file mode 100644 index 0000000000..c34e6f018c --- /dev/null +++ b/serverless-operator-examples/serverless-workflow-inventory/resources/01-configmap_01-order-resources.yaml @@ -0,0 +1,62 @@ +apiVersion: v1 +data: + supplier.yaml: | + --- + openapi: 3.0.3 + info: + title: Supplier API + version: 1.0.0-SNAPSHOT + tags: + - name: supplier + description: Supplier Sample + paths: + /supplier/{supplier-id}: + post: + tags: + - Supplier + operationId: sendOrder + parameters: + - name: supplier-id + in: path + required: true + schema: + type: string + requestBody: + content: + text/plain: + schema: + type: string + responses: + "200": + description: OK + content: + text/plain: + schema: + type: string + delete: + tags: + - Supplier + operationId: cancelOrder + parameters: + - name: supplier-id + in: path + required: true + schema: + type: string + requestBody: + content: + text/plain: + schema: + type: string + responses: + "200": + description: OK + content: + text/plain: + schema: + type: string +kind: ConfigMap +metadata: + creationTimestamp: null + name: 01-order-resources + namespace: my-workflows diff --git a/serverless-operator-examples/serverless-workflow-inventory/resources/01-sonataflow_order.yaml b/serverless-operator-examples/serverless-workflow-inventory/resources/01-sonataflow_order.yaml new file mode 100644 index 0000000000..f994ff07d8 --- /dev/null +++ b/serverless-operator-examples/serverless-workflow-inventory/resources/01-sonataflow_order.yaml @@ -0,0 +1,179 @@ +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlow +metadata: + annotations: + sonataflow.org/description: Order Workflow Sample + sonataflow.org/expressionLang: jq + sonataflow.org/profile: dev + sonataflow.org/version: "1.0" + creationTimestamp: null + labels: + app: order + name: order + namespace: my-workflows +spec: + flow: + events: + - correlation: + - contextAttributeName: orderid + dataOnly: true + kind: consumed + name: orderEvent + source: Client + type: OrderEventType + - correlation: + - contextAttributeName: orderid + dataOnly: true + kind: consumed + name: shippingEvent + source: Shipper + type: ShippingEventType + - correlation: + - contextAttributeName: orderid + dataOnly: true + kind: consumed + name: cancelEvent + source: Client + type: CancelEventType + functions: + - name: printMessage + operation: sysout + type: custom + - name: sendOrder + operation: specs/supplier.yaml#sendOrder + type: rest + - name: cancelOrder + operation: specs/supplier.yaml#cancelOrder + type: rest + start: + stateName: Order Received + states: + - exclusive: true + name: Order Received + onEvents: + - actionMode: sequential + eventDataFilter: + useData: true + eventRefs: + - orderEvent + transition: + nextState: Check Inventory + type: event + - actionMode: sequential + actions: + - actionDataFilter: + fromStateData: . + results: '{inventory: .item | test("0+") }' + useResults: true + functionRef: + arguments: + message: '"Check Inventory " + .orderId' + invoke: sync + refName: printMessage + name: printAction + name: Check Inventory + transition: + nextState: Item Available? + type: operation + - dataConditions: + - condition: .inventory + transition: + nextState: Prepare for Shipping + defaultCondition: + transition: + nextState: Forward to External Supplier + name: Item Available? + type: switch + - actionMode: sequential + actions: + - actionDataFilter: + useResults: true + functionRef: + arguments: + message: '"Prepare for Shipping"' + invoke: sync + refName: printMessage + name: printAction + name: Prepare for Shipping + transition: + nextState: Order Shipped or Cancelled + type: operation + - actionMode: sequential + actions: + - actionDataFilter: + useResults: true + functionRef: + arguments: + content: .orderId + supplier-id: '"1"' + invoke: sync + refName: sendOrder + name: sendOrderRestCall + name: Forward to External Supplier + transition: + nextState: Order Shipped or Cancelled + type: operation + - exclusive: true + name: Order Shipped or Cancelled + onEvents: + - actionMode: sequential + eventDataFilter: + useData: true + eventRefs: + - shippingEvent + - actionMode: sequential + eventDataFilter: + data: '{cancel:true}' + useData: true + eventRefs: + - cancelEvent + transition: + nextState: Is Shipped? + type: event + - dataConditions: + - condition: .cancel == true + name: order cancelled + transition: + nextState: Compensate Order + defaultCondition: + transition: + nextState: Notify Customer + name: Is Shipped? + type: switch + - actionMode: sequential + actions: + - actionDataFilter: + useResults: true + functionRef: + arguments: + message: '"Compensate Order"' + invoke: sync + refName: printMessage + name: printAction + end: + compensate: true + terminate: true + name: Compensate Order + type: operation + - actionMode: sequential + actions: + - actionDataFilter: + useResults: true + functionRef: + arguments: + message: '"Notify Customer"' + invoke: sync + refName: printMessage + name: printAction + end: + terminate: true + name: Notify Customer + type: operation + resources: + configMaps: + - configMap: + name: 01-order-resources + workflowPath: specs +status: + address: {} + lastTimeRecoverAttempt: null diff --git a/serverless-operator-examples/serverless-workflow-inventory/resources/02-configmap_order-props.yaml b/serverless-operator-examples/serverless-workflow-inventory/resources/02-configmap_order-props.yaml new file mode 100644 index 0000000000..87a490e40b --- /dev/null +++ b/serverless-operator-examples/serverless-workflow-inventory/resources/02-configmap_order-props.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +data: + application.properties: | + # Generate OpenAPIs with operationId + mp.openapi.extensions.smallrye.operationIdStrategy=METHOD + + # OpenAPIs endpoint + quarkus.rest-client.supplier_yaml.url=https://order-swf-supplier-kubesmarts.rhba-0ad6762cc85bcef5745bb684498c2436-0000.us-south.containers.appdomain.cloud +kind: ConfigMap +metadata: + creationTimestamp: null + labels: + app: order + name: order-props + namespace: my-workflows