Using persistence in SonataFlow workflows

This document describes how to configure a SonataFlow instance to use persistence and store the workflow context in a relational database.

Kubernetes’s pods are stateless by definition. In some scenarios, this can be a challenge for workloads that require maintaining the status of the application regardless of the pod’s lifecycle. In the case of SonataFlow, by default, the context of the workflow is lost when the pod restarts.

If your workflow requires recovery from such scenarios, you must provide additional configuration to enable the Workflow Runtime Persistence. That configuration must be provided by using the SonataFlowPlatform CR or the SonataFlow CR, and has different scopes depending on each case.

Configuring the persistence using the SonataFlowPlatform CR

The SonataFlowPlatform CR facilitates the configuration of the persistence with namespace scope. It means that it will be automatically applied to all the workflows deployed in that namespace. This can be useful to reduce the amount resources to configure, for example, in cases where the workflows deployed in that namespace belongs to the same application, etc. That decision is left to each particular use case, however, it’s important to know, that this configuration can be overridden by any workflow in that namespace by using the SonataFlow CR.

Finally, the SonataFlow Operator can also use this configuration to set the supporting service’s persistence.

Persistence configurations are applied at workflow deployment time, and potential changes in the SonataFlowPlatform will not impact already deployed workflows.

To configure the persistence you must use the persistence field in the SonataFlowPlatform CR spec:

SonataFlowPlatform CR persistence configuration example
apiVersion: sonataflow.org/v1alpha08
kind: SonataFlowPlatform
metadata:
  name: sonataflow-platform-example
  namespace: example-namespace
spec:
  persistence:
    postgresql:
      serviceRef:
        name: postgres-example (1)
        namespace: postgres-example-namespace (2)
        databaseName: example-database (3)
        port: 1234 (4)
      secretRef:
        name: postgres-secrets-example (5)
        userKey: POSTGRESQL_USER (6)
        passwordKey: POSTGRESQL_PASSWORD (7)
1 Name of the Kubernetes Service to connect with the PostgreSQL database server.
2 (Optional) Kubernetes namespace containing the PostgreSQL Service. Defaults to the SonataFlowPlatform’s local namespace.
3 Name of the PostgreSQL database to store the workflow’s data.
4 (Optional) Port number to connect with the PostgreSQL Service. Defaults to 5432.
5 Name of the Kubernetes Secret containing the username and password to connect with the database.
6 Name of the Kubernetes Secret key containing the username to connect with the database.
7 Name of the Kubernetes Secret key containing the password to connect with the database.

This configuration signals the operator that every workflow deployed in the current SonataFlowPlatform’s namespace must be properly configured to connect with that PostgreSQL database server. And the operator will add the relevant JDBC connection parameters in the form of environment variables to the workflow container.

Additionally, for SonataFlow CR deployments that use the preview profile, it will configure the SonataFlow build system to include specific Quarkus extensions required for persistence.

Currently, PostgreSQL is the only supported persistence.

Below you can see an example of the configurations produced for a workflow with the name example-workflow, that was deployed using the previous SonataFlowPlatform. For simplicity, only the env configurations related to the persistence has been included. These operator managed configurations are immutable.

Generated persistence env configurations in the workflow container
      env:
        - name: QUARKUS_DATASOURCE_USERNAME
          valueFrom:
            secretKeyRef:
              name: postgres-secrets-example
              key: POSTGRESQL_USER
        - name: QUARKUS_DATASOURCE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-secrets-example
              key: POSTGRESQL_PASSWORD
        - name: QUARKUS_DATASOURCE_DB_KIND
          value: postgresql
        - name: QUARKUS_DATASOURCE_JDBC_URL
          value: >-
            jdbc:postgresql://postgres-example.postgres-example-namespace:1234/sonataflow?currentSchema=example-workflow
        - name: KOGITO_PERSISTENCE_TYPE
          value: jdbc

When you use the SonataFlowPlatform persistence, every workflow is configured to use a PostgreSQL schema name equal to the workflow name.

To learn how to initialize the database schema see: Database schema initialization.

Configuring the persistence using the SonataFlow CR

The SonataFlow CR facilitates the configuration of the persistence with workflow scope, and you can use it independently if the SonataFlowPlatform persistence was already configured in the current namespace, see: Persistence configuration precedence rules.

To configure the persistence, you must use the persistence field in the SonataFlow CR spec:

SonataFlow CR persistence configuration example
apiVersion: sonataflow.org/v1alpha08
kind: SonataFlow
metadata:
  name: example-workflow
  annotations:
    sonataflow.org/description: Example Workflow
    sonataflow.org/version: 0.0.1
spec:
  persistence:
    postgresql:
      serviceRef:
        name: postgres-example (1)
        namespace: postgres-example-namespace (2)
        databaseName: example-database (3)
        databaseSchema: example-schema (4)
        port: 1234 (5)
      secretRef:
        name: postgres-secrets-example (6)
        userKey: POSTGRESQL_USER (7)
        passwordKey: POSTGRESQL_PASSWORD (8)
  flow:
     ...
1 Name of the Kubernetes Service to connect with the PostgreSQL database server.
2 (Optional) Kubernetes namespace containing the PostgreSQL Service. Defaults to the workflow’s local namespace.
3 Name of the PostgreSQL database to store the workflow’s data.
4 (Optional) Name of the database schema to store workflow’s data. Defaults to the workflow’s name.
5 (Optional) Port number to connect with the PostgreSQL Service. Defaults to 5432.
6 Name of the Kubernetes Secret containing the username and password to connect with the database.
7 Name of the Kubernetes Secret key containing the username to connect with the database.
8 Name of the Kubernetes Secret key containing the password to connect with the database.

This configuration signals the operator that the current workflow must be properly configured to connect with that PostgreSQL database server when deployed. Similar to the SonataFlowPlatform persistence, the operator will add the relevant JDBC connection parameters in the form of environment variables to the workflow container.

Additionally, for SonataFlow CR deployments that use the preview profile, it can configure the SonataFlow build system to include specific Quarkus extensions required for persistence.

Currently, PostgreSQL is the only supported persistence.

To learn how to initialize the database schema see: Database schema initialization.

Persistence configuration precedence rules

And, if the current namespace has an already configured SonataFlowPlatform CR persistence, the following rules apply:

  • If the SonataFlow CR has a configured persistence, that configuration will apply.

  • If the SonataFlow CR has no configured persistence, i.e., the field spec.persistence is not present at all, the persistence configuration will be taken from the current platform.

  • If you don’t want the current workflow to use persistence, you must use the following configuration in the SonataFlow CR: spec.persistence : {} to ignore the SonataFlowPlatform persistence configuration.

Persistence configuration and SonataFlow profiles

All the configurations shown for the SonataFlowPlatform CR and SonataFlow CR, apply exactly the same for both the preview and the gitops profiles. However, you must not use them in the dev profile, since this profile will simply ignore them.

Finally, the only distinction between preview and gitops profiles is that, when you use the gitops profile, the following Quarkus extensions must be added when you build your workflow image. Since that build is accomplished outside the operator scope.

groupId artifactId version

io.quarkus

quarkus-agroal

3.8.4

io.quarkus

quarkus-jdbc-postgresql

3.8.4

org.kie

kie-addons-quarkus-persistence-jdbc

999-SNAPSHOT

If you generate your images by using the kogito-swf-builder, you can do it by passing it the following build argument:

QUARKUS_EXTENSIONS=io.quarkus:quarkus-agroal:3.8.4,io.quarkus:quarkus-jdbc-postgresql:3.8.4,org.kie:kie-addons-quarkus-persistence-jdbc:999-SNAPSHOT

Database schema initialization

When you use the SonataFlow PostgreSQL persistence, you can either opt to use Flyway to produce the database initialization, or manually upgrade your database via DDL scripts.

Flyway managed database initialization

To enable Flyway you must use any of the following configuration procedures:

The Flyway schema initialization is disabled by default.

Flyway configuration by using the workflow ConfigMap

Add the following property to your workflow ConfigMap.

Example of enabling Flyway by using the workflow ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app: example-workflow
  name: example-workflow-props
data:
  application.properties: |
    quarkus.flyway.migrate-at-start = true

Flyway configuration by using the workflow container env vars

Add the following env var in the spec.podTemplate.container of the SonataFlow CR.

Example of enabling Flyway by using the workflow container env vars
apiVersion: sonataflow.org/v1alpha08
kind: SonataFlow
metadata:
  name: example-workflow
  annotations:
    sonataflow.org/description: Example Workflow
    sonataflow.org/version: 0.0.1
spec:
  podTemplate:
    container:
      env:
        - name: QUARKUS_FLYWAY_MIGRATE_AT_START
          value: 'true'
  flow: ...

Flyway configuration by using SonataFlowPlatForm properties

To apply a common Flyway configuration to all the workflows in a given namespace, you can use the spec.properties.flow of the SonataFlowPlatform in that namespace.

Example of enabling Flyway by using the SonataFlowPlatform properties.
apiVersion: sonataflow.org/v1alpha08
kind: SonataFlowPlatform
metadata:
  name: sonataflow-platform
spec:
  properties:
       flow:
          - name: quarkus.flyway.migrate-at-start
            value: true

The configuration above takes effect at workflow deployment time, so you must be sure that the property is configured before you deploy your workflows.

Manual database initialization by using DDL

To initialize the database schema manually, you must be sure that the following application property quarkus.flyway.migrate-at-start is not configured, or is set to false, and follow this procedure.

Remember that:

  • By default, every workflow is configured use a schema name equal to the workflow name, and thus, that manual initialization must be applied for every workflow.

  • When you use the SonataFlow CR persistence configuration it is possible to use the schema name of your choice.

Conclusion

By using the SonataFlowPlatform CR you can enable the persistence for all the workflows that you deploy in that namespace. And, by using the SonataFlow CR you can enable the persistence of a particular workflow. If both methods are present in the current namespace, the SonataFlow CR configuration has precedence over the SonataFlowpPlatform configuration.

Found an issue?

If you find an issue or any misleading information, please feel free to report it here. We really appreciate it!