Skip to main content

Introducing Formengine - The New Formbuilder, try for FREE formengine.io.

Multitenancy

In Quick Start we covered how to configure the Web API in single-tenant mode. In that mode, the API works with one tenant whose identifier is WorkflowApiConstants.SingleTenantId.

For most scenarios, this is sufficient to run Workflow Engine, and you don’t need to think about tenants or other multi-tenant details. Single-tenant mode simply hides those details from you.

Configuration

In the Web API, a tenant is represented by a combination of TenantId, WorkflowRuntime, and a database provider. A single database provider can serve multiple WorkflowRuntime instances, and each runtime can handle requests from multiple tenants.

Tenants that differ only by TenantId but are served by the same WorkflowRuntime are called logical tenants. Tenants that are served by different WorkflowRuntime instances are called physical tenants.

To enable multi-tenant mode, use AddWorkflowTenants instead of AddWorkflowRuntime. Provide a list of options that describe the physical tenants to create. For example:

builder.Services.AddWorkflowTenants(
new WorkflowTenantCreationOptions
{
// First physical tenant creation options.
TenantIds = ["MsSqlTenant1", "MsSqlTenant2"],
PersistenceProviderId = PersistenceProviderId.Mssql,
ConnectionString = "Server=localhost,1433;Database=master;User Id=SA;Password=MyPassword;"
},
new WorkflowTenantCreationOptions
{
// Second physical tenant creation options.
TenantIds = ["PostgresTenant1", "PostgresTenant2"],
PersistenceProviderId = PersistenceProviderId.Postgres,
ConnectionString = "Host=localhost;Port=5432;Database=postgres;User Id=postgres;Password=MyPassword;"
}
);

// Don't forget to register the database providers you use.
builder.Services.AddWorkflowApiMssql();
builder.Services.AddWorkflowApiPostgres();

This example defines two physical tenants. The first serves the logical tenants MsSqlTenant1 and MsSqlTenant2 using the Microsoft SQL Server provider, and the second serves PostgresTenant1 and PostgresTenant2 using the PostgreSQL provider.

Key options in WorkflowTenantCreationOptions:

  1. TenantIds — the list of logical tenant identifiers that will be handled by this WorkflowRuntime and database provider (i.e., by this physical tenant).
  2. PersistenceProviderId — the identifier of the database provider factory used to create both IWorkflowProvider and IDataProvider. If omitted, the first registered provider will be used. The selected provider must be registered as a service. Available IDs are defined in the PersistenceProviderId class.
  3. ConnectionString — the database connection string used to create providers. You can define multiple physical tenants that use the same provider factory but different connection strings.

The remaining options in WorkflowTenantCreationOptions let you fine-tune how WorkflowRuntime and providers are created.

Usage

When calling the API in multi-tenant mode, you can explicitly specify TenantId via the WorkflowApiConstants.TenantIdHeader request header ("Workflow-Api-Tenant-ID"). If the header is missing, DefaultTenantId is used, which by default is WorkflowApiConstants.SingleTenantId.

In multi-tenant mode, it is recommended to set DefaultTenantId to null. This ensures that every API request must explicitly provide a TenantId; otherwise, the request is rejected with an error.

When a TenantId is provided, the Workflow API resolves the physical tenant that serves the given logical tenant. The request is then processed by the corresponding WorkflowRuntime and database provider.

Using the ASP.NET service provider, you can access all tenants via the IWorkflowTenantRegistry service. If you are in the context of an HTTP request, you can retrieve the current tenant with IWorkflowTenantRegistry.GetHttpContextWorkflowTenant or via an extension method on IServiceProvider.

public class MyController : ControllerBase
{
private readonly IWorkflowTenantRegistry _tenantRegistry;

public MyController(IWorkflowTenantRegistry tenantRegistry)
{
_tenantRegistry = tenantRegistry;
}

[HttpGet("my-endpoint")]
public IActionResult MyEndpoint()
{
var currentTenant = _tenantRegistry.GetHttpContextWorkflowTenant();
WorkflowRuntime runtime = currentTenant.WorkflowRuntime;
// Use currentTenant here...
return Ok();
}
}
Stay in the know
Build Workflow Applications Faster
Star us on GitHub