Inventory Logic

In this section, you will expand the workflow logic to manage a first stage of fictional use case.

The use case

As any other tutorial use case, the situation we are going to consider is somewhat realistic, but for sake of simplicity we are going to oversee many real aspects. The primary goal is to show the key capabilities of the Serverless Workflow specification, please, apologise for the many naiveties that domain experts can easily point out.

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 a 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 an high level design:

high level flow

The final use case will be implemented going through a set consecutive sprints[1], in every sprint you are going to experience a new feature of the Serverless Workflow specification.

The Inventory Sprint

In this sprint we are going to add the check inventory operation and based on the outcome call a prepare for shipping or forward to external supplier.

  1. Open order.sw.json file

  2. Replace Order Received with Check Inventory in the following places:

    • start

    • name of the state

    • the message

      To change all occurrences in one shot: select Order Received, press twice CTRL-D, perform the rename, then press ESC
  3. Add after the functionRef object the following logic:

    "actionDataFilter": {
      "fromStateData": ".",
      "results": "{inventory: .item | test(\"0+\") }"
    }

    This code mocks up the check inventory logic: actionDataFilter is a feature to manipulate the workflow data (state scoped), in practical terms it gets the item value and create a new data inventory which value can be true or false if the item contains one or more 0

    The previous logic is an example of the JQ expression language which plays a key role in Serverless Workflow. To evaluate and manipulate data is crucial to gaining some familiarity with this language Understanding JQ expressions
  4. Move the cursor to the end of previous state, type a comma and you should get the suggestion pop up

    vscode suggestion
  5. Select New switch state, then edit the name and the condition:

    {
      "name": "Item Available?",
      "type": "switch",
      "dataConditions": [
      {
        "condition": ".inventory",
        "transition": "Transition to another state if condition is true"
      }
      ],
      "defaultCondition": {
        "transition": "Default transition of the workflow"
      }
    }
  6. Go back to Check Inventory state and replace the end declaration with transition to point to the switch state:

    "transition": "Item Available?"
  7. After the switch state definition add a new operation state for Prepare for Shipping:

    {
      "name": "Prepare for Shipping",
      "type": "operation",
      "end": true,
      "actions": [
        {
          "name": "printAction",
          "functionRef": {
            "refName": "printMessage",
            "arguments": {
              "message": "\"Prepare for Shipping\""
            }
          }
        }
      ]
    },
  8. Add an operation state for Forward to External Supplier:

    {
      "name": "Forward to External Supplier",
      "type": "operation",
      "end": true,
      "actions": [
        {
          "name": "printAction",
          "functionRef": {
            "refName": "printMessage",
            "arguments": {
              "message": "\"Forward to External Supplier\""
            }
          }
        }
      ]
    },
  9. Update the switch state to point to the correct operation states:

    • for the conditional branch set the transition to Prepare for Shipping

      vscode suggestion 2
    • for the default condition set the transition to Forward to External Supplier

This is the expected result:

inventory final

You can compare your resulting workflow with the expected solution at this stage in solution/01-inventory

Test the workflow logic

Before connecting the workflow to an external service is a good idea to probe it in isolation (i.e. smoke test): in fact, the current actions only print messages in the console.

  1. Open the http probing file: src/test/resources/probe.http

  2. Identify the first POST request in the file and just above it click on Send Request

    send request

  3. Check the results and the workflow execution in the quarkus console

  4. Repeat the previous 2 steps to check that the workflow execution follow the other branch (Forward to External Supplier)

Call an external REST service

Serverless Workflow have a straightforward integration with OpenAPIs.

For sake of simplicity, the project contains a Simple REST resource which exposes two operations:

  • sendOrder to send order to a supplier

  • cancelOrder to send an order cancellation to a supplier

The link between the workflow and the rest service is the OpenAPIs spec file.

The Serverless Workflow expects to find the file in the src/main/resources/specs folder and since the startup project already provide it, you can easily consume it from workflow definition file:

  1. Inspect the OpenAPI yaml file at src/main/resources/specs/supplier.yaml

  2. Open workflow definition src/main/resources/order.sw.json

  3. Go in the functions definition section, add a comma to the last definition the editor will propose you the two operation available, accept the suggestion and add both definitions

    vscode suggestion 3
  4. Identify the Forward to External Supplier state

    you can click on state in the workflow diagram and the tool will bring you on the state definition line in the textual representation.
  5. Replace the print action with the function call:

    {
      "name": "sendOrderRestCall",
      "functionRef": {
        "refName": "sendOrder",
        "arguments": {
          "supplier-id":"\"1\"",
          "content":".orderId"
        }
      }
    }
    The rest service is invoked with two arguments, a dummy supplier-id (1) and the orderId.

You can compare your resulting workflow with the expected solution at this stage in solution/02-rest

Test the external REST service

Repeat the test you did before.

In the log file you should notice a different output coming from the REST implementation:

2022-12-22 12:58:02,859 INFO  [org.kie.kog.ser.wor.dev.DevModeServerlessWorkflowLogger] (executor-thread-0) Triggered node 'Forward to External Supplier' for process 'order' (e6cdca5b-795c-407a-8c4d-a58ef3e59bc4)
2022-12-22 12:58:02,860 INFO  [org.kie.kog.ser.wor.dev.DevModeServerlessWorkflowLogger] (executor-thread-0) Triggered node 'sendOrder' for process 'order' (e6cdca5b-795c-407a-8c4d-a58ef3e59bc4)
Supplier 1 received the order order-123

CONGRATULATION!!! Now your Serverless Workflow call a REST service!

You can also notice that the workflow invocation returns a different payload. What’s changed? Why?

1. A Sprint is an iteration in the Agile methodology, which aims to be time-boxed, self container and always executable.