Skip to content

Viewing workflows

Stephan Pelikan edited this page Oct 11, 2026 · 7 revisions

Business applications often want to show a workflow. That means the BPMN diagram of the process and, coloured on top of it, what already happened in that concrete workflow. VanillaBP provides everything a BPMN viewer such as bpmn.io needs. It does so for every BPMS (business process management system), through the same three methods of ProcessService:

List<ProcessDefinition> getProcessDefinitions(A workflowAggregate, String historyContext);
InputStream            getBpmnXml(String processDefinitionId);
WorkflowHistory        getWorkflowHistory(A workflowAggregate, String historyContext);

The methods only read. Nothing is persisted, no transaction is required and the workflow does not move on. The record types ProcessDefinition, WorkflowHistory and WorkflowElementHistory are documented in the SPI's README.

  1. The three parts
    What each of the three methods returns, and in which order a viewer calls them.
  2. Digging into call activities
    How a viewer goes down into a called process, level by level.
  3. Process definition ids are opaque
    Why the id has to travel back unchanged, and what VanillaBP put into it.
  4. Ended workflows
    How long a finished workflow can still be shown.
  5. Right after the start
    Why a viewer opened seconds after the start still sees the workflow on an eventually consistent BPMS.
  6. Errors
    The two exceptions and what each of them means.
  7. BPMS specifics
    Which data a BPMS can serve, and where the gaps are written down.

The three parts

  1. getProcessDefinitions(aggregate, null) returns the definition the workflow runs on. Its usedByElements is null. It also returns the definitions its call activities would call next, and each of them names the call-activity elements which use it. So a simple process without call activities returns exactly one entry.
  2. getBpmnXml(processDefinitionId) returns the BPMN XML of one of those definitions. Give it to the viewer.
  3. getWorkflowHistory(aggregate, null) returns when the workflow started and when it ended, if it did. It also returns the history of its elements in execution order. For each element this is the element id, the start and end time, whether it was canceled, and an error message if the element is in error right now. Use the element ids to colour the diagram.

Digging into call activities

Once a call activity was executed, its WorkflowElementHistory has a secondaryWorkflowHistoryContext. Pass that value back as the historyContext argument to look at the called workflow. Then getProcessDefinitions returns the definition which that instance actually runs on, plus ITS call activities. And getWorkflowHistory returns its element history. This way a viewer lets users go down the tree of processes level by level.

Process definition ids are opaque

Never parse, build or shorten a ProcessDefinition#id(), and the same for the processDefinitionId inside a WorkflowHistory. VanillaBP puts the adapter id which can resolve it in front of the BPMS' own id. The reason: a workflow may run in any of the configured BPMS, and getBpmnXml has no workflow aggregate to find the BPMS from. Pass the id back unchanged. A viewer may of course carry it in a URL.

Ended workflows

Viewing is not limited to running workflows. As long as the BPMS still holds the workflow's data, you get definitions and history for ended workflows too. Most viewers show exactly these. Once the BPMS has cleaned the data up (history retention), a WorkflowNotFoundException says so and tells you what to do.

Right after the start

Some BPMS answer from a read model which is only eventually consistent. Camunda 8, for example, searches its query API, and an exporter fills that API. Such a BPMS reports a workflow created moments ago as unknown, although it is running. A viewer opened right after the start is exactly this case, so a read waits. VanillaBP often knows which BPMS holds the workflow, because it started it there or got a delivery of it. It reads this from the row it wrote when the workflow started, which is in your database. So a second node and a node after a restart know it too. Then it asks that BPMS again until the workflow shows up or the BPMS' own window has passed. For Camunda 8 this is workflow-visibility-timeout, 10 seconds by default. In normal operation the wait is one to three seconds, and your call returns the history it asked for.

VanillaBP does not wait for a workflow which nobody recorded. A wrong id fails at once, as it should. If the window passes without an answer, the WorkflowNotFoundException names the BPMS which was expected to hold the workflow. An exporter which has stopped looks exactly like one which is a moment behind, so you need that name.

Errors

  • WorkflowNotFoundException: no configured BPMS knows the workflow. It was never started, or started elsewhere, or its history was cleaned up, or an expected BPMS stayed silent for the whole window above.
  • ProcessDefinitionNotFoundException: the given definition id is malformed, or belongs to an adapter which is not configured (any more), or names a definition the BPMS does not hold any more.

BPMS specifics

Which data a BPMS can serve differs. Some record every flow node, some only activities, some no element history at all. A remote BPMS may also lag behind (eventual consistency) or need additional infrastructure. If an adapter serves less than the API offers, its Deviations page says so:

  1. Camunda 7: Learn more...
  2. Camunda 8: Learn more...
  3. bpm-crafters Process-Engine-API: Learn more...

Clone this wiki locally