Repository navigation
Integration SPI
VanillaBP brings its own answer to a handful of questions. Where is a workflow aggregate stored? In which transaction does a handler run? Where does a planned call to the BPMS (business process management system) wait for your commit? These answers fit the usual application. The integration SPI (service provider interface) lets an application which is not the usual one replace one of them with its own. You rarely need it. If your aggregates live in a persistence VanillaBP already supports, you need nothing from this page.
Technically it is the counterpart of the SPI for Java.
The SPI for Java is the API your code calls and is annotated with, for example @WorkflowTask and
ProcessService. Here you find interfaces which your code implements instead. VanillaBP then calls
your answer where it needs something only your application can know.
-
Why it is an artifact of its own
Why these interfaces are not part of the SPI for Java, although business code implements them. -
What you can implement
The five contracts, and the page which explains each of them. -
How it reaches your build
The support modules, and why a workflow module depends on one of them.
The SPI for Java is the API a business application is written against. Every entry of its decision log is a promise to that application. It has a release line of its own, and version 2 of the platform did not change it. A workflow module compiles against the same artifact as before.
The integration SPI describes contracts of the runtime which calls them. An outbox and a log of
processed deliveries exist because of how VanillaBP works inside, and they grow with it. So they are
released with the platform integration, as io.vanillabp:vanillabp-integration-spi in the package
io.vanillabp.integration.spi. If they were part of the SPI for Java, every addition to the runtime
would change the API which business code is written against. And a workflow module would see
interfaces it has no reason to know about.
| Interface | What you take over | Explained on |
|---|---|---|
AggregatePersistenceAware<A> |
loading and saving an aggregate in a persistence VanillaBP does not know, for example an event store or a ledger | Workflow aggregates |
TransactionRunner, TransactionRunnerAware<A>
|
the unit of work VanillaBP puts around everything it does with one aggregate, for stores which the platform's transaction does not reach | Workflow aggregates |
PhaseTwoOutbox, PhaseTwoOutboxAware<A>
|
the store which holds work planned for after your commit, both calls to a BPMS and an extension's own operations; useful if you already have outbox infrastructure | Spring Boot, Quarkus |
TaskDeliveryLog, TaskDeliveryLogAware<A>
|
the record which stops a task delivered again from running your handler twice | Workflow tasks |
WorkflowAdapterCache |
remembering which BPMS holds a workflow, in a cache your cluster shares | BPMS migration |
The *Aware<A> variants answer the same question per aggregate, not for the whole application. An
application with more than one kind of persistence needs that. The most specific implementation
wins. The aggregate class an implementation names may be a superclass or an interface, so one bean
can serve a whole workflow module.
The election cache is part of the integration SPI on purpose and not something internal. It is the recommended answer when asking the BPMS becomes the bottleneck of a cluster. And that answer has to be infrastructure which the application already runs (why).
A few more types are in the same artifact: Election, PhaseOperation, PhaseTwoCall, StoredKey.
An outbox store of your own has to use them. They are documented where they are needed. A workflow
service never touches them.
You add no dependency for it. Both platform support modules bring the artifact as a transitive dependency:
-
io.vanillabp:vanillabp-spring-boot-supporton Spring Boot -
io.vanillabp:vanillabp-quarkus-supporton Quarkus
A pure workflow module depends on a support module. The support module provides what the workflow module needs to compile: the VanillaBP APIs. On purpose it does not provide the API of any BPMS, so you cannot break the hexagonal architecture by accident. On both platforms it is a plain library without platform infrastructure. This is why the application module needs more on top of it: the adapter on Spring Boot, and the core extension plus the adapter on Quarkus.
In the module which builds the application the artifact arrives anyway. On Spring Boot it comes
through the adapter, on Quarkus through vanillabp-quarkus-integration. In both cases
io.vanillabp:vanillabp-bom manages its version, so you never write a <version>.
