Flowable-rest multi-tenancy support

See: 19.4. Multitenancy

Multitenancy in general is a concept where the software is capable of serving multiple different organizations. Key is that the data is partitioned and no organization can see the data of other ones. In this context, such an organization (or a department, or a team or whatever, is called a tenant .

Note that this is fundamentally different from a multi-instance setup, where a Flowable Process engine instance is running for each organization separately (and with a different database schema). Although Flowable is lightweight, and running a Process Engine instance doesn’t take much resources, it does add complexity and more maintenance. But, for some use cases it might be the right solution.

Multitenancy in Flowable is mainly implemented around partitioning the data. It is important to note that Flowable does not enforce multi tenancy rules . This means it will not verify when querying and using data whether the user doing the operation belongs to the correct tenant. This should be done in the layer calling the Flowable engine. Flowable does make sure that tenant information can be stored and used when retrieving process data.

When deploying process definition to the Flowable Process engine it is possible to pass a tenant identifier . This is a string (e.g. a UUID, department id, etc.), limited to 256 characters which uniquely identifies the tenant:

repositoryService.createDeployment()
            .addClassPathResource(...)
            .tenantId("myTenantId")
            .deploy();

Passing a tenant ID during a deployment has following implications:

  • All the process definitions contained in the deployment inherit the tenant identifier from this deployment.
  • All process instances started from those process definitions inherit this tenant identifier from the process definition.
  • All tasks created at runtime when executing the process instance inherit this tenant identifier from the process instance. Standalone tasks can have a tenant identifier too.
  • All executions created during process instance execution inherit this tenant identifier from the process instance.
  • Firing a signal throw event (in the process itself or through the API) can be done whilst providing a tenant identifier. The signal will only be executed in the tenant context: i.e. if there are multiple signal catch events with the same name, only the one with the correct tenant identifier will actually be called.
  • All jobs (timers and async continuations) inherit the tenant identifier from either the process definition (e.g. timer start event) or the process instance (when a job is created at runtime, e.g. an async continuation). This could potentially be used for giving priority to some tenants in a custom job executor.
  • All the historic entities (historic process instance, task and activities) inherit the tenant identifier from their runtime counterparts.
  • As a side note, models can have a tenant identifier too (models are used e.g. by the Flowable modeler to store BPMN 2.0 models).

To actually make use of the tenant identifier on the process data, all the query API’s have the capability to filter on tenant. For example (and can be replaced by the relevant query implementation of the other entities):

runtimeService.createProcessInstanceQuery()
    .processInstanceTenantId("myTenantId")
    .processDefinitionKey("myProcessDefinitionKey")
    .variableValueEquals("myVar", "someValue")
    .list()

The query API’s also allow to filter on the tenant identifier with like semantics and also to filter out entities without tenant id.

Important implementation detail: due to database quirks (more specifically: null handling in unique constraints) the default tenant identifier value indicating no tenant is the empty string . The combination of (process definition key, process definition version, tenant identifier) needs to be unique (and there is a database constraint checking this). Also note that the tenant identifier shouldn’t be set to null, as this will affect the queries since certain databases (Oracle) treat empty string as a null value (that’s why the query .withoutTenantId does a check against the empty string or null). This means that the same process definition (with same process definition key) can be deployed for multiple tenants, each with their own versioning. This does not affect the usage when tenancy is not used.

Do note that all of the above does not conflict with running multiple Flowable instances in a cluster.

[Experimental] It is possible to change the tenant identifier by calling the changeDeploymentTenantId(String deploymentId, String newTenantId) method on the repositoryService . This will change the tenant identifier everywhere it was inherited before. This can be useful when going from a non-multitenant setup to a multitenant configuration. See the Javadoc on the method for more detailed information.