Skip to main content
Version: Next 🚧

Configuration

Application configuration can be supplied through:

  • file: configured by env CONFIG_FILE (yaml/json format)
  • env variables

Root Configuration:​

Top-level configuration object.

FieldTypeDescription
httpServerHttpServerConfiguration of the public REST server
grpcServerGrpcServerConfiguration of the public GRPC server
tracingTracingTracing and observability configuration
clusterClusterCluster and Raft consensus configuration

Server Configuration: Server​

Defines settings for the public REST API server.

FieldTypeEnv VariableDefaultDescription
contextstringREST_API_CONTEXT/Base context path for the API
addrstringREST_API_ADDR:8080Address the server binds to
maxRequestBodyBytesint64REST_API_MAX_REQUEST_BODY_BYTES10485760Maximum request body size for all HTTP endpoints except /system/v1/cluster/restore (10 MiB); larger bodies receive HTTP 413
logModestringREST_API_LOG_MODEerrorsWhich requests are logged: errors (status >= 400 only), all, or off
logBodyboolREST_API_LOG_BODYfalseInclude request/response bodies in logged requests. Buffers every body in memory, so keep off on busy servers

GRPC Server Configuration: GrpcServer​

Defines settings for the GRPC API server.

FieldTypeEnv VariableDefaultDescription
addrstringGRPC_API_ADDR:9090Address the GRPC server listens on

Cluster Configuration: Cluster​

Settings related to clustering, internal communication, and Raft consensus.

FieldTypeEnv VariableDefaultDescription
nodeIdstringCLUSTER_NODE_IDβ€”Unique node identifier
addrstringCLUSTER_RAFT_ADDR:8090Bind address for internal Raft communication
advstringCLUSTER_RAFT_ADV(same as addr)Advertised Raft address
raftClusterRaftβ€”β€”Raft-specific cluster settings
cdcCDCβ€”β€”Change Data Capture output settings
persistencePersistenceβ€”β€”Persistence and caching configuration
engineEngineβ€”β€”BPMN engine behaviour settings

Engine Configuration: Engine​

Behaviour settings for the BPMN engines running on the node partitions.

FieldTypeEnv VariableDefaultDescription
maxProcessInstanceNestingDepthint64CLUSTER_ENGINE_MAX_PROCESS_INSTANCE_NESTING_DEPTH100Maximum allowed nesting depth of a process instance in the parent-child chain (call activities, sub processes, multi-instance bodies). Creating a child instance deeper than the limit stops execution and raises an incident describing a potential infinite loop. Values <= 0 disable the check.
maxProcessInstanceFlowNodeCountint64CLUSTER_ENGINE_MAX_PROCESS_INSTANCE_FLOW_NODE_COUNT10000Maximum total number of flow node executions allowed within one process instance. Guards against infinite sequence-flow loops (e.g. an exclusive gateway looping back without a reachable exit condition). Exceeding the limit fails the token and raises an incident. Values <= 0 disable the check.

Resolving a nesting-depth incident retries the blocked execution instead of bypassing the configured limit. For an event-subprocess trigger, resolution recreates the consumed message subscription or timer; if the limit is unchanged, the next matching message or timer firing raises another incident. Raise or disable the limit only after confirming that the process model cannot create an unbounded instance chain.

The two limits serve different constraints and are intentionally independent: maxProcessInstanceNestingDepth bounds the depth of parent→child instance chains (rarely legitimate above double digits), while maxProcessInstanceFlowNodeCount bounds the total number of flow node executions within a single instance (legitimate loops may run thousands of iterations), hence its much larger default. The flow node counter is kept in the flow_node_count column of the process_instance table (like nesting_depth) and is removed together with the rest of the instance data during history cleanup. Resolving a flow-node-count incident resets the instance's counter to zero, granting a fresh execution budget. Resolve it only after fixing the loop's exit condition (for example, by correcting process variables); otherwise the guard trips again once the fresh budget is consumed. Resolving other incident types does not alter the flow node counter.

When upgrading a cluster that already has active process instances, counting starts at zero for those instances when the migration is applied. Existing audit history is intentionally not used to reconstruct runtime counters because audit rows may already have been removed by history cleanup.


Raft Configuration: ClusterRaft​

Raft consensus and cluster joining settings.

FieldTypeEnv VariableDefaultDescription
dirstringCLUSTER_RAFT_DIRzen_bpm_node_dataPath to local node data
nonVoterboolCLUSTER_RAFT_NON_VOTERfalseSet node as non-voting member
joinAttemptsintCLUSTER_RAFT_JOIN_ATTEMPTS5Number of join attempts
joinIntervaldurationCLUSTER_RAFT_JOIN_INTERVAL2sTime interval between join attempts
joinAddresses[]stringCLUSTER_RAFT_JOIN_ADDRESSESβ€”List of node addresses to join
bootstrapExpectintCLUSTER_RAFT_BOOTSTRAP_EXPECT0Minimum nodes for bootstrap
bootstrapExpectTimeoutdurationCLUSTER_RAFT_EXPECT_BOOTSTRAP_TIMEOUT10sMax timeout for expected bootstrap nodes

RqLite Change Data Capture​

Output settings for exporting RqLite changes from voting partition nodes.

FieldTypeEnv VariableDefaultDescription
enabledboolRQLITE_CDC_ENABLEDfalseEnables RqLite CDC export
outputstringRQLITE_CDC_OUTPUTβ€”HTTP(S) endpoint, stdout, or advanced JSON output settings path
serviceIdstringRQLITE_CDC_SERVICE_IDβ€”Required base service identifier; ZenBPM appends the partition suffix

CDC is disabled by default. Enable it on every voting RqLite partition node:

cluster:
cdc:
enabled: true
output: https://consumer.example.com/rqlite/cdc
serviceId: orders-production-v1

The equivalent environment configuration is:

RQLITE_CDC_ENABLED=true
RQLITE_CDC_OUTPUT=https://consumer.example.com/rqlite/cdc
RQLITE_CDC_SERVICE_ID=orders-production-v1

RQLITE_CDC_ENABLED is the authoritative switch. When it is unset or false, CDC is disabled even if an output is present. When it is true, the output is passed to rqlite as an HTTP(S) endpoint, the special value stdout, or a path to an advanced JSON output settings file. Invalid files, endpoints, or TLS settings fail startup. CDC startup also fails unless a non-empty service identifier is configured through serviceId, RQLITE_CDC_SERVICE_ID, or an advanced output file.

Initial data and replica consistency​

CDC does not create an initial snapshot or backfill. Rows already present in SQLite when CDC is enabled are not emitted; only changes captured after CDC starts are sent. Seed a new consumer with an explicit export or other backfill, and reconcile that baseline with subsequent CDC events.

All voting replicas of a partition must use the same endpoint and compatible CDC settings. In practice, deploy the same effective configuration, including the service identifier (serviceId or advanced service_id), table_filter, row_ids_only, and TLS and delivery settings, to every voting replica. Only the current leader transmits events, while acknowledged high-water marks are shared with followers. If replicas use different endpoints or filtering settings, a leader change can split the stream between consumers or cause a follower to discard events acknowledged through a different endpoint. CDC is rejected on non-voting nodes.

Endpoint cutover​

ZenBPM publishes to one CDC endpoint and does not provide built-in dual delivery or backfill. Prefer a stable, durable receiver URL and change its downstream routing when moving consumers. The receiver can retain events while the new consumer is seeded and then forward them without changing the ZenBPM nodes.

If the endpoint must change in ZenBPM itself, do not roll the change through a live cluster. Instead:

  1. Pause writes that can produce CDC events.
  2. Let the old endpoint acknowledge all outstanding deliveries for every partition, and verify its durable ledger is caught up.
  3. Stop the voting replicas, apply the same new endpoint and compatible CDC settings to all of them, and restart them without allowing a mixed-config replica set to serve writes or elect a leader.
  4. Resume writes only after every voting replica is using the new configuration.

The new endpoint receives only post-cutover changes. Copy or backfill the existing state separately if it needs a complete projection.

Stable service identifiers​

cluster.cdc.serviceId configures the required base identifier for direct endpoint and stdout outputs. ZenBPM appends -partition-N, so a base value of orders-production-v1 emits orders-production-v1-partition-1 for partition 1.

An advanced rqlite CDC output settings file can also set service_id. For example:

{
"endpoint": "https://consumer.example.com/rqlite/cdc",
"service_id": "orders-production-v1"
}

Point every node at the file through the CDC output setting:

RQLITE_CDC_ENABLED=true
RQLITE_CDC_OUTPUT=/etc/zenbpm/rqlite-cdc-output.json

Use an absolute path and make the file and any referenced TLS files available on every voting node. A non-empty service_id in this file takes precedence over cluster.cdc.serviceId and RQLITE_CDC_SERVICE_ID. This preserves the advanced output file as the authoritative source for its delivery settings. If the file omits service_id, configure the base identifier through cluster.cdc.serviceId or RQLITE_CDC_SERVICE_ID instead.

Keep the effective base identifier (serviceId or advanced service_id) identical on all replicas and stable across restarts, leader changes, scaling, node replacement, and endpoint cutovers while the same Raft history continues. Choose a new unique base value before starting with fresh storage, cloning an environment, or resetting or rewinding Raft history. Those operations can reuse Raft indexes; retaining the old identifier could make an existing consumer ledger mistake new changes for duplicates.

CDC batches may be delivered more than once. Consumers should acknowledge only durably stored events and deduplicate each transaction group by (service_id, payload.index). If a consumer splits events into separate records, it must add the event's array position to that key.

ZenBPM exports the persistent queue length, endpoint retry count, and confirmed high-water mark for every CDC-enabled partition replica through GET /system/metrics. See the observability reference for metric names and the stalled-delivery alert.


Persistence Configuration: Persistence​

Configuration for caching and storage.

FieldTypeEnv VariableDefaultDescription
instanceHistoryTTLtypes.TTLPERSISTENCE_INSTANCE_HISTORY_TTL0TTL for finished process instances
procDefCacheTTLtypes.TTLPERSISTENCE_PROC_DEF_CACHE_TTL_SECONDS24hTTL for cached process definitions
procDefCacheSizeintPERSISTENCE_PROC_DEF_CACHE_SIZE200Max number of cached process definitions
decDefCacheTTLtypes.TTLPERSISTENCE_DEC_DEF_CACHE_TTL_SECONDS24hTTL for cached dmn resource definitions
decDefCacheSizeintPERSISTENCE_DEC_DEF_CACHE_SIZE200Max number of cached dmn resource definitions
rqlite*RqLiteβ€”β€”Configuration for embedded RQLite database
migrationMigrationβ€”β€”Configuration for SQL migration

SQL Migration Configuration: Migration​

Configuration for caching and storage.

FieldTypeEnv VariableDefaultDescription
dirstringPERSISTENCE_MIGRATION_DIRinternal/sql/migrationsConfiguration for SQL migration directory

Tracing Configuration: Tracing​

Distributed tracing settings using OpenTelemetry.

FieldTypeEnv VariableDefaultDescription
enabledboolTRACING_ENABLEDfalseEnable or disable tracing
namestringTRACING_APP_NAMEZenBPMApplication name for tracing
transferHeaders[]stringTRACING_TRANSFER_HEADERSβ€”HTTP headers to propagate through trace context
endpointstringOTEL_EXPORTER_OTLP_ENDPOINTβ€”OTLP exporter endpoint (e.g., for Jaeger/Tempo)
samplerRatiofloat64TRACING_SAMPLER_RATIO1.0Fraction of new traces sampled (0.0 - 1.0); child spans follow their parent's sampling decision

Error Tracking: GlitchTip​

ZenBPM reports recovered panics and explicitly marked invariant violations to GlitchTip. Error tracking uses environment variables rather than the application configuration file so it can initialize before configuration parsing.

Env VariableDefaultDescription
SENTRY_ENABLEDtrueMaster switch for error reporting. Set to false to disable it even when DSN is set.
SENTRY_DSNβ€”GlitchTip project DSN. Error reporting is disabled when it is unset or empty.
SENTRY_ENVIRONMENTCurrent PROFILE valueDeployment environment attached to each event.

The application build version is attached as the GlitchTip release. Sentry performance tracing and automatic log forwarding are disabled because ZenBPM uses OpenTelemetry for tracing and reports only actionable unexpected errors.


Example YAML Configuration​

name: zenbpm
httpServer:
context: /
addr: :8080
maxRequestBodyBytes: 10485760
grpcServer:
addr: :9090
cluster:
addr: localhost:8090
adv: localhost:8090
persistence:
migration:
dir: internal/sql/migrations
raft:
dir: node-1
bootstrapExpect: 1
bootstrapExpectTimeout: 30s
joinAttempts: 5
joinAddresses:
- localhost:8090
nodeId: node-1
tracing:
enabled: true
endpoint: localhost:4318
name: ZenBPM