Skip to content

History / Spring Boot integration

Revisions

  • docs: when a cancelation arrives, and what the election carries Workflow tasks: the @TaskEvent paragraph said cancelation was a property of the BPMS and left it there. It now says when the event arrives on a remote BPMS, which is at the end of the workflow and at the next job of the same workflow, what that does not catch, and how to switch the check off. The schema paragraph names the second index the delivery table needs. BPMS migration: the election may carry the BPMS' own id of the workflow, what an adapter may do with it and what it may never do with it. Extensions: a section of its own about which BPMS holds a workflow, the two calls, and what an extension may do with the workflow id. Both platform pages: the delivery table gets the indexes its reads need, not only the one its retention deletes by. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23

    @stephanpelikan stephanpelikan committed Sep 19, 2026
  • docs(outbox): the youngest call replaces the one still waiting An extension whose call carries a payload carries a state, and the entry which waited holds the older one. It may now say replacingWhatIsStillWaiting() and go to scheduleReplacingWhatIsStillWaiting, and the waiting entry gets the younger call instead of dropping it. The extensions page gets the section with the example, what happens to the payload of the entry which was replaced, and the one entry which is never replaced. Both platform pages get it in the list of what the outbox guarantees, including what a store of your own has to implement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RYPiyZ32jQQhqYKx44cw23

    @stephanpelikan stephanpelikan committed Sep 17, 2026
  • docs(extensions): work an extension plans for after the commit The outbox is open to extensions, and a call of theirs may now carry the state they saw at their sync point. The new section says what that gets an extension author, what it costs and where the bytes lie; the two platform pages name the third table in the list of changelog properties. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 317c593d1dc4f979b02bced2fe22416d596a1c0b)

    @stephanpelikan stephanpelikan committed Sep 17, 2026
  • docs: a rejected dispatch is planned again instead of waited for The gruelbox store used to wait out the window of a workflow its BPMS had not made searchable yet, on its dispatching thread. It cannot: gruelbox dispatches inside a transaction of its own, and a rejected attempt leaves that transaction unable to commit. The attempt now ends and the entry is planned again with the window the adapter named, so the page says where that window is written and what the store adds to it. The migration page promised one to three seconds for a Camunda 8 workflow which was not searchable yet. What decides is the adapter's window, so the page says that and where to lower it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019HSy3LqLy3SDHdP4ojgZb2

    @stephanpelikan stephanpelikan committed Sep 13, 2026
  • docs(schema): the indexes are part of the tables An application which applies the schema artifact itself has to apply them too, so both platform pages say which indexes there are, what the question behind them is and what it costs without them: 11 to 18 ms of sequential scan against 0.05 ms on PostgreSQL 16 with 200000 rows. They also say what happens where VanillaBP created the tables in an earlier version: the boot names the missing index and the statement which adds it rather than creating it itself, because that takes a lock for as long as the table is large. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re2yjHbaFRvnHyW61E3sao

    @claude claude committed Sep 12, 2026
  • docs(outbox): the poll interval is a cap, not a rhythm The poller asks its store when the earliest entry it owes something to is due and sleeps until then, so an entry goes out at its due time whatever the interval says. Both platform pages said the opposite, in the property comment and next to the statement which reopens a blocked entry. What the interval still bounds is work a node wrote down before it went away, which is where the cluster page now says why no node wakes another and why a database notification was not the answer. Observability gains the other half: a sleeping poller takes the heartbeat away, so the page says which number tells a quiet system from a stalled one now, and where to look in a thread dump. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re2yjHbaFRvnHyW61E3sao

    @claude claude committed Sep 12, 2026
  • docs(outbox): the store waits for the deployment on every store Spring Boot answers requests before the models reached the BPMS, and until now the gruelbox store carried a start arriving in that window to a BPMS which does not hold the process. It waits for the first poll now, like the stores VanillaBP owns, so the page says what a reader has to expect at an application start: one poll interval at worst, and no start blocked for having been early. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re2yjHbaFRvnHyW61E3sao

    @stephanpelikan stephanpelikan committed Sep 11, 2026
  • docs(outbox): a blocked gruelbox entry keeps its key The per-store table promises that a key deduplicates only what is still waiting. Gruelbox holds it until the row is gone, blocked entries included, so a repetition of the operation is refused while the row waits for repair. That was reachable after block-after-attempts before and is reachable on the first attempt now that a failure the adapter calls permanent blocks right away, which is reason enough to write it down next to the other two things a JPA application inherits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re2yjHbaFRvnHyW61E3sao

    @stephanpelikan stephanpelikan committed Sep 11, 2026
  • docs(outbox): a start which never happens is blocked and visible Observability gains vanillabp.outbox.blocked, the counter of entries a store gave up on. It needs a row of its own because vanillabp.outbox.pending falls at that very moment: a blocked entry stops waiting, so the gauge an operator watches moves as if the backlog had drained. Starting workflows now says that on a remote BPMS the start finishes after the caller's commit, that the second half can fail with nobody in the application listening, and where to look when it does. The retry curve stays on the platform pages, which the section links to. Both platform pages point the operations duty at the new counter and say which values the error of a blocked entry names. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re2yjHbaFRvnHyW61E3sao

    @stephanpelikan stephanpelikan committed Sep 11, 2026
  • docs: what gruelbox does with a workflow which is not searchable yet The page said that this store knows one fixed distance and left it there, which was true for a failed dispatch and misleading for the one case an application notices most: a message correlated right after its workflow was started. That entry carries the window its BPMS needs, and gruelbox now waits it out instead of coming back after attempt-frequency. The paragraph says both halves, because the second one is the price: the thread waiting is the one dispatching this store, so everything else waiting in it waits along, and an application which cannot afford that runs the JDBC store.

    @stephanpelikan stephanpelikan committed Sep 4, 2026
  • docs: the retry distance grows, and a blocked entry no longer blocks itself Both platform pages described the old envelope: thirty seconds ten times, about five minutes, and a BPMS away for longer turned every pending operation into a row somebody opened by hand. The distance grows now, attempt-frequency doubling up to max-attempt-frequency, and the pages say what the two ends answer - the cap decides how quickly a returned BPMS is noticed, the attempt budget decides which outage the store survives on its own. The dead end goes with it: blocking releases the deduplication key on the stores VanillaBP owns, so a repaired entry has to be expected next to a second row for the same operation. Where gruelbox cannot follow, the Spring Boot page says so in the place its other differences already stand: one fixed distance instead of the growing one, and a request id held until the row is removed. Story 195, carrying the wiki text of story 186. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    @stephanpelikan stephanpelikan committed Sep 3, 2026
  • docs: the page is called integration SPI The artifact is io.vanillabp:vanillabp-integration-spi, so the wiki calls the thing what its coordinate calls it instead of inventing a second name. Page renamed, all links and the glossary entry follow. The adapter SPI is gone from the wiki: it is nothing a reader of these pages implements. Where the start instant explains its own name, the reason is now VanillaBP's rather than an SPI the page never introduces. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjxJNwTRcKzTmXCwLU7Wi4

    @stephanpelikan stephanpelikan committed Sep 1, 2026
  • docs: a page for the business SPI, testing parked The wiki mentioned the business SPI and the two support modules without ever saying what they are or why they exist. Business-SPI.md answers both: the two APIs and their directions, why these interfaces are released with the platform instead of with the SPI for Java, the five contracts an application may implement, and how the artifact reaches a build. Linked from Home, the migration page, both platform pages and the aggregates page. Migrating from version 1 no longer mentions states version 2 passed through on its way, and no longer names the Process-Engine-API adapter: version 1 had no support for that BPMS, so nobody upgrades from it. Testing.md moves to parked/Testing.md.txt. GitHub creates a page for every file with a markup extension, so the .txt keeps it out of the wiki's page list while the text stays in the history until the reworked testing strategy arrives with the blueprints. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjxJNwTRcKzTmXCwLU7Wi4

    @stephanpelikan stephanpelikan committed Sep 1, 2026
  • docs: how long the outbox tries, and the way back An operator was told that blocked entries need manual attention and neither how long the framework tries before an entry becomes one nor what that attention is. Both platform pages now name the envelope as the product of attempt-frequency and block-after-attempts, say that a blocked entry stays in the store on purpose and that retention never removes it, and carry the way back: the statement for VanillaBP's own stores, gruelbox' unblock for the JPA default on Spring Boot, and the at-least-once consequence of reopening an entry next to it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjxJNwTRcKzTmXCwLU7Wi4

    @stephanpelikan stephanpelikan committed Aug 31, 2026
  • docs: one blank line between paragraphs, on the two platform pages Removing the note markers left a double blank line behind. One appearance for all pages means one blank line here too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    @stephanpelikan stephanpelikan committed Aug 31, 2026
  • docs: every page opens with what to do and carries a table of contents A reader who has never used VanillaBP met the reasoning for a rule before the rule itself, and had no way of telling how far to read before writing a first workflow. The pages now start with the sentence somebody can act on and keep the background where it belongs, further down. Nothing was deleted; what explains a rule moved behind it. Every page gained a numbered table of contents in the shape Home and the Spring Boot page already used, so a reader sees the sections and what each of them answers before scrolling. Where a first heading only repeated the title GitHub shows above the page, it is gone and the page starts with its first sentence. Home is now ordered the way a newcomer needs it, and what VanillaBP is sized for became a page of its own: it answers a question somebody asks before they start, not one they trip over in the middle of the introduction. The architecture picture from the repository's diagrams folder is embedded there, linking to its Excalidraw source. The horizontal rules of the workflow-module pages are gone, the heading is the separator everywhere else. Hints are written as sentences rather than marked with a label, headings sit at one depth per page, and the paragraphs written by hand over the last months were brought to the tone of the rest without changing a single statement they make. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    @stephanpelikan stephanpelikan committed Aug 31, 2026
  • docs: completing a task reads the record instead of asking a BPMS The delivery record of a task names the BPMS which handed that task out, so completeTask and cancelTask are routed from it and a second call is the warned no-op without a round trip. Workflow-tasks gets the section which explains it and what happens where no record answers; BPMS-migration says that this is the one operation for which a shared election cache buys nothing, and the two platform pages name the column and the index the store needs for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjxJNwTRcKzTmXCwLU7Wi4

    @stephanpelikan stephanpelikan committed Aug 30, 2026
  • docs: a dependency example carries the version you can paste The rule is about prose: a version named in a sentence reads 2.0, the release line without a patch digit. A Maven or Gradle coordinate is not prose - it is copied into a build, where 2.0 resolves to nothing - so the examples carry 2.0.0 again, and the Camunda 8 ones 2.0.0-8.9, with the suffix naming the cluster minor the artifact was built against. The sentence which told the reader to fill in a patch himself is gone with it; where it is useful to know which patches exist, the pages link Maven Central instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CvgyhjwTEh834mwbptZZxh

    @stephanpelikan stephanpelikan committed Aug 28, 2026
  • docs: a rule says where its decision is written down Five decision logs hold 61 entries, the wikis linked none of them, and 22 of the 42 objections an outside review raised were already answered in one. A reader who wondered why a rule is what it is had no way there short of reading source repositories. So a rule carries a (why) link now, pointing at the numbered entry which decided it. Home says once what the links are and where the logs live, and the form is the same on every page of every wiki: an inline link at the end of the sentence stating the rule. Numbers are handed out once and never reused, so the links keep resolving. The rules the review named are linked first - the outbox on Camunda 7, probing per operation, the two retentions, sharing aggregate values, the Camunda 8 correlation key - and the remaining entries follow wherever a page states their rule. BPMS-adapters also says in one sentence what the module migration-adapter is, which it linked without explaining. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CvgyhjwTEh834mwbptZZxh

    @stephanpelikan stephanpelikan committed Aug 27, 2026
  • docs: why FULL is the default, what the stores differ in, and what the trigger time is Three gaps the review found on these pages. Workflow-aggregates stated the default and not its reason, so a reader minimising with @NoSyncWithBPMS could not tell which side to minimise. The reasons are portability and an upgrade from version 1 which must not touch code, and neither of them says that sharing everything is right: what to aim for is as little as possible and as much as needed, which means the class annotated @NoSyncWithBPMS and @SyncWithBPMS on the attributes the process decides by plus the ones an operator has to see in Operate or Cockpit. The page also names what ignoring it costs, payload per command on Camunda 8 and a serialization format on Camunda 7. The same page says when the values arrive, which differs: inside the engine transaction on Camunda 7, with the completing command on the other two, so only there can a failure leave the aggregate ahead of the BPMS. The outbox guarantees were stated for every store, and "DONE, not deleted" does not hold for the gruelbox store of a JPA application: it deletes a dispatched row to free the key, and it counts an attempt only when one failed, so a hard crash re-dispatches without the probe which mitigates a duplicate start. The Spring Boot page carries a table per store now, says what follows for a JPA application, and says that a future version replaces that default with the JDBC store Quarkus uses. The Quarkus page points there for whoever runs both. Starting-workflows called the aggregate's id the timer's trigger time. No engine reports the scheduled time, so what an embedded engine answers is the moment the instance was created, which costs nothing because both are written in one transaction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CvgyhjwTEh834mwbptZZxh

    @stephanpelikan stephanpelikan committed Aug 27, 2026
  • docs: the pages follow the decisions taken since 2026-08-11 Camunda 7 progresses a workflow after the caller's commit, through the outbox, since story 63. Three pages still described the model before it: correlating a message, broadcasting a signal and pushing a changed aggregate all said an embedded BPMS does the work inside the caller's transaction. They now say what every adapter does, with the reason in one sentence - a command which loses a concurrency conflict leaves the caller's transaction rollback-only, so it cannot be repeated there. The ordering paragraph of Workflow-aggregates loses its embedded exception for the same reason: an embedded BPMS is dispatched by the same outbox and promises no order either. A workflow module's configuration file carries defaults again (2026-08-21), so the Spring Boot and Quarkus pages stop promising it higher priority than the application's own files. Workflow-modules-in-Spring-Boot no longer says VanillaBP scans the classpath for workflow services: they are found among the bean definitions since 2026-08-26, which changes what a module nobody scanned looks like at startup. The migration guide's property table said retry-backoff is "not yet in version 2". It is back on the Camunda 8 adapter, PT10S by default and resolvable down to a single task, so the row now points there instead of asking readers to report it. Versions read 2.0 everywhere, without a patch digit and without -SNAPSHOT, and the pages which introduce the BOM say once what that means for a build. Two anchors were dead, workflow-visibility-timeout on the Camunda 8 Configuration page and a section about the aggregate's ID which does not exist on Workflow-aggregates. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CvgyhjwTEh834mwbptZZxh

    @stephanpelikan stephanpelikan committed Aug 27, 2026
  • docs(delivery): the retention of a delivery record is its own property vanillabp.delivery.retention decides how long a record is kept, and it follows vanillabp.outbox.retention only where it is not set. The pages now say which of the two numbers is about correctness and which one is about support, that the new one is read globally rather than per workflow module, and what makes a period long enough - including the part nobody can compute for the reader, how long the application is stopped.

    @stephanpelikan stephanpelikan committed Aug 27, 2026
  • docs(correlation): what an idempotency key deduplicates, and what a loop has to do The key deduplicates the operations still waiting for their dispatch, so the second round of a loop correlating the same message with the same correlation id reaches the BPMS instead of being swallowed for the retention period. What still collides is two correlations planned in one unit of work, and a multi-instance call activity is where the sameness of the aggregate is not the application's choice - so the page says to vary the correlation id per round and per element, and that VanillaBP warns about every discard. Camunda 8 gets a section of its own: the cluster deduplicates by message id for the message time-to-live, one hour by default, which is the longer of the two nets and shortened by no VanillaBP setting. The outbox sections of both platform pages say what the retention still buys after this, and `Workflow-tasks` says that the same property decides correctness on the inbound side. Story 128. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CvgyhjwTEh834mwbptZZxh

    @stephanpelikan stephanpelikan committed Aug 26, 2026
  • docs: VanillaBP notices the leftovers of a renamed adapter id Story 120 makes the rule of story 119 checkable: at startup VanillaBP asks its own stores which adapter ids they still hold waiting outbox entries or records of open tasks for, and names one which is not configured any more, with both readings and both remedies. BPMS-migration says what the message looks like, why it warns instead of failing the boot, and how 'vanillabp.retired-adapters' quits the leftovers of a finished migration. It also names the two limits: a store which cannot answer keeps the check silent (the gruelbox-based outbox is one, its entries are a serialized invocation), and a rename while nothing is left is undetectable and costs nothing. Both platform pages list the new property. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7HLKaJvVpdCiSYxhwHJTc

    @stephanpelikan stephanpelikan committed Aug 23, 2026
  • docs: an adapter id is a name to choose once and never rename Story 119 showed how easily an adapter id is taken for a label. It is not: VanillaBP persists it to know what belongs to which BPMS, so a rename is a new adapter next to workflows nothing serves any more. BPMS-migration gets the authoritative section: why a speaking id is worth choosing up front (which cluster, which database, SaaS next to on-premises, and a migration between two Camunda 8 configurations needs two names anyway), a caution that an id must never be renamed while workflows run, and a table of what a rename costs - the open START entries of the outbox, the delivery key of every processed delivery, the election cache and the process definition ids an application already holds. Both platform pages say in their convention list that "the type defaults to its ID" exists for applications upgrading from version 1 rather than as a recommendation, and point at that section. Migrating-from-version-1 says the same where an upgrader reads it: keep the id while one BPMS is all you run, and know that the second one cannot be had by renaming the first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7HLKaJvVpdCiSYxhwHJTc

    @stephanpelikan stephanpelikan committed Aug 23, 2026
  • Merge remote-tracking branch 'origin/master' into feature/finalize # Conflicts: # Quarkus-integration.md # Spring-Boot-integration.md

    @stephanpelikan stephanpelikan committed Aug 22, 2026
  • docs: what keeps the record of a task nobody has completed The record answering the redeliveries of an open task used to expire with vanillabp.outbox.retention while the task was still open, and the page said so as a boundary to plan around. It is not one any more: the retention counts from the last redelivery the record answered, the moment the handler ran is a second timestamp which never moves, and the age of an open task keeps being measured from that one. Also said on both platform pages: a store of your own decides how long its records live, and stillOpen is what VanillaBP calls on every redelivery it answers from a record. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    @stephanpelikan stephanpelikan committed Aug 20, 2026
  • docs: what a Flyway instance of its own needs, per platform Story 96, from what the blueprint persistence-flyway measured on both platforms. Story 75 recommended a Flyway instance with a history table of its own for VanillaBP's SQL and did not say what that costs. On Spring Boot it needs baselineOnMigrate, because every instance but the first finds a schema full of somebody else's tables and refuses to touch it, and baselineVersion("0") with it, because the default baseline is version 1 and would mark every migration numbered 1.0.0 as applied while reporting success. Named the FlywayMigrationInitializer as well: the entity manager factory waits for beans of that type, not for Flyway beans. On Quarkus the recommendation does not hold at all. The extension applies one configuration per datasource, a named one without its datasource is skipped without a word, and a migration run of the application's own comes after Hibernate has already validated the schema. The page now describes the shape which does work there: one timeline for every owner, with the version ranges kept apart, and VanillaBP numbering its own in 2.x. Both pages point at the blueprints persistence-liquibase and persistence-flyway, where both shapes have a test behind them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    @stephanpelikan stephanpelikan committed Aug 19, 2026
  • docs: the outbox table on Spring Boot belongs to gruelbox Story 95. Handing the schema over with 'vanillabp.outbox.create-schema: false' switches gruelbox's migrator off together with VanillaBP's table creation, and a custom table name does the same silently. The page said so in three lines and left the reader to find the statements; it now says that the table is checked at startup like VanillaBP's own two, and where the statements come from: DefaultPersistor.writeSchema(Writer) emits gruelbox's migrations for the configured dialect, so nothing has to be copied out of its source. Also noted what that output does and does not contain: TXNO_SEQUENCE belongs to it, TXNO_VERSION does not, being the bookkeeping of the migrator just switched off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    @stephanpelikan stephanpelikan committed Aug 19, 2026
  • docs: how long a delivery is remembered Story 76. The deduplication window was the retention period alone. It becomes: until the workflow ends, or until the retention passed, whichever comes first - and with the new option switched off the old sentence still holds. Workflow-tasks gets the section, next to what a repeated delivery does; both platform pages get the property and the note that a store of its own which cannot delete is named at startup. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jss55UjjvxYcLQPVFUFe25

    @stephanpelikan stephanpelikan committed Aug 19, 2026