Release Notes
1.0.x
| Version | Date |
|---|---|
1.0.0 |
2026-10-22 |
1.0.0
Breaking changes
-
A production build carrying Goblin fails (#86): Goblin must never reach production. Declare
quarkus-goblin,quarkus-goblin-metricsandquarkus-goblin-opentelemetrywith<scope>provided</scope>in Maven — dev mode and@QuarkusTestkeep them, the packaged application does not contain them — or asquarkusDevandtestImplementationdependencies in Gradle. Until now a production build shipped the inactive extension; it now stops withGoblin must never reach productionand the way to fix it. See Does Goblin run in production?. Code compiled fromsrc/mainmust not use the Goblin API either — it would fail in the packaged application — so a dev or test build now refuses it and names the class: move anAssaultObserveror a customAssaulttosrc/test/java, or to an indexed module declaredprovided. The check covers the main classes of the application module and of the other modules of the build it packages. Remote dev mode (mutable-jar) cannot carry Goblin.-
Vert.x
WebClient`s are armed automatically: in dev and test builds, Goblin rewrites the `WebClient.create(…)andWebClient.wrap(…)calls of the application classes — the application module’s main and test classes and the other modules of the build — core or Mutiny, to attach its interceptor, so theGoblinWebClient.enable(…)call around them is no longer needed — and must go, since it would reach production.GoblinWebClient.enableremains for a client the rewrite does not see (a method reference such asWebClient::create, a reflective call), from test code or aprovidedmodule.
-
-
Public API defined and frozen for semantic versioning (#85): the public Java API is the
io.quarkiverse.goblinpackage, everything else moved toio.quarkiverse.goblin.internaland is not covered. See Public API and versioning for the contract and the versioning policy.-
AssaultEngineandMutableAssaultConfigare now interfaces, and the configuration is split in two:AssaultConfigis a read-only view (the getters),MutableAssaultConfigextends it with the setters. Read-only views —MutableAssaultConfig.snapshot(),AssaultEngine.configSnapshot(), both sides ofAssaultConfigChange,AssaultContext.getConfig()and the parameter ofAssault.isEnabled— are now typedAssaultConfig, so a customAssaultdeclaresisEnabled(AssaultConfig).getLatencyRange()is no longer public: readgetLatencyMinMs()andgetLatencyMaxMs()on a snapshot.HeaderRulemoved toAssaultConfig.HeaderRule, still reachable asMutableAssaultConfig.HeaderRule. -
These interfaces carry only the methods an application calls; their implementation is internal. Injecting
AssaultEngineworks as before, butnew AssaultEngine()andnew MutableAssaultConfig()no longer compile, and the plumbing used by the assault hooks and the Dev UI is no longer public: on the engineshouldAssault,shouldAssaultClient,resolveAssaultLayer,drawLevelGate,recordAssault,HTTP_REQUEST_LAYERSandMESSAGE_LAYERS; on the configurationfromConfig,validateAndFix,setOnChange,workingCopy,replaceWith,loadClass,describeResponseHeaders,isValidResponseHeaderName,isValidResponseHeaderValueandEXCEPTION_PRESETS;ResponseHeaderAction.parse. -
The built-in assaults, the filters, the layer hooks, the configuration mappings and the other implementation classes moved from
io.quarkiverse.goblin,io.quarkiverse.goblin.assault,.route,.service,.databaseand.messagingtoio.quarkiverse.goblin.internaland its sub-packages. -
AssaultEngine.AssaultRecordhas two new components,assaultTypeandinjectedValue(see below): its canonical constructor changed, and the five-argument constructor defaulting the source toSERVERis removed. Records are created by Goblin; an observer test building them by hand passes the source and the type. -
The moved classes log under their new names, e.g.
io.quarkiverse.goblin.internal.AssaultEngineImplinstead ofio.quarkiverse.goblin.AssaultEngine, andio.quarkiverse.goblin.internal.filter.GoblinChaosFilterinstead ofio.quarkiverse.goblin.GoblinChaosFilter. A log level set on an old class category no longer applies: set it onio.quarkiverse.goblin, which covers them all. -
The
AssaultSPI (Assault,AssaultContext,AssaultOutcome) is part of the stable public API: still bound to JAX-RS, it only evolves by additions,Assaultgainingdefaultmethods only. A custom assault records itself with the newAssaultContext.record(this)instead ofcontext.getEngine().recordAssault(…).
-
Improvements
-
The extension moves from preview to stable status: its public API — including the
AssaultSPI — follows semantic versioning (see Public API and versioning). -
AssaultEngine.AssaultRecordgains anassaultType()component, theAssaultTypeof the recorded assault, next to thetype()label: an observer can filter assaults without parsing labels such asresponse-body-truncate. The label is unchanged, and so are thetypemetric tag and thegoblin.assault.typespan attribute. -
Resilience testing guides (#88): one page per Fault Tolerance pattern — circuit breakers, retries and fallbacks — each with the layer to arm, a Dev UI walkthrough on the sample application, a
@QuarkusTest, what to observe in the history and theft_*metrics, and the pitfalls; and performance baselines, measuring the reference latency from the client and the server before injecting a known delay. The sample application gains a circuit breaker that recovers in 500 ms and an outgoing REST Client call guarded by@Timeoutand@Fallback, both covered by the integration tests. -
Structured assault logs (#87): every assault, chaos switched on or off, an auto-off scheduled and every configuration change is logged as a single
key=valueline in theio.quarkiverse.goblin.eventscategory — timestamp, method, assault type, injected value, configuration snapshot — with the same fields in the MDC for JSON logs. Assaults are logged atINFO, the lifecycle atWARN. See Structured logs.-
The startup banner
Chaos engineering active: …is replaced by anactivatedevent, and the per-action Dev UIWARNlogs (Goblin latency ENABLED via Dev UI,Goblin target level changed…) by theconfig-change,activatedanddeactivatedevents, which also cover a change made through JSON-RPC, Dev MCP or the Java API. The kill switch, the reset to defaults, an import and a scenario load still name the action, atINFO. -
AssaultEngine.AssaultRecordgains aninjectedValue()component (842ms,HTTP 503,java.lang.IllegalStateException: boom…), also returned asinjectedValueby the JSON-RPCgetHistory, shown in the Markdown report, set as thegoblin.assault.injected_valuespan attribute, and used as theinjected_valuetag ofgoblin_assaults_total(-for a latency, whose value is in the latency timer, so the tag stays bounded).
-
-
A custom
Assaultdeclared without a scope annotation is registered@ApplicationScoped, as the SPI expects, instead of@Dependent.
Bug Fixes
-
A REST Client latency cut short by a
@Timeoutis recorded as the delay actually endured, not the one drawn: the history, theassaultevent (value=), thegoblin.assault.latency_msspan attribute and thegoblin.latency.injected.secondstimer no longer report a 2000 ms delay for a call the timeout ended after 400 ms. The layer faults (SERVICE,DATABASE,MESSAGING) already did.
0.5.x
| Version | Date |
|---|---|
0.5.0 |
2026-10-20 |
0.5.0
Improvements
-
Reactive routes: when the application has
quarkus-reactive-routes, theHTTP_INlayer also assaults@Routemethods, with no code change: latency, exception, HTTP status, dependency degradation, response body and response header, recorded with the same labels as a REST resource (#64). On the event loop the latency uses a Vert.x timer, so the loop is never blocked; an injected exception is answered by the router’s failure handlers, including@Route(type = FAILURE)methods, which are never assaulted themselves, and a request is assaulted once, by the first@Routeit reaches, even when a pass-through route sits in front of a REST resource. A route is also an entry point for theSERVICEandDATABASElayers below it, and an excluded-package route shields its request like an excluded resource. Reactive-route classes are no longer woven by theSERVICElayer, just like JAX-RS resources. The response body is rewritten when a route ends its response in one go, streamed responses are left untouched, and customAssaultbeans are not applied to reactive routes. In the Dev UI, theInbound RESTlayer and theRESTsource chip are renamedInbound HTTPandinbound HTTP, since they cover both. -
The
goblinfeature is only registered in dev and test builds: a production application no longer listsgoblinamong its installed features, consistent with the chaos wiring that was already left out of a production build.
0.4.x
| Version | Date |
|---|---|
0.4.0 |
2026-10-03 |
0.4.0
Improvements
-
getStatusreportsinactiveReason(manual,auto-off,disabled,test-mode,launch-mode; absent while active) and the Dev UI status bar shows the reason next toInactive, so a silent dashboard is no longer a mystery. -
AssaultObservergainsonConfigChange(AssaultConfigChange): observers see every configuration change, once per published change (a wholeapplyConfigincluded), with the configuration before and after it as read-only snapshots, in dev and test mode — enough to record the exact attack an application went through and replay it after a fix (#71). The method has a default no-op, so existing observers are unaffected. -
The Chaos Dashboard and History pages show an animated goblin in their bottom-right corner while chaos is active, and hide it when chaos is off (a still image for reduced motion).
-
Saved scenarios: save the current assault configuration as a named scenario under
.goblin/scenarios/, then load or delete it from the new Scenarios section of the Dev UI, through JSON-RPC (listScenarios,saveScenario,loadScenario,deleteScenario) or Dev MCP, wherelistScenariosis enabled by default and the three others are opt-in (#49). -
Agent playbook and resilience inventory: two Dev MCP resources, enabled by default, for an AI agent driving Goblin (#72).
quarkus-goblin_agentPlaybookis the playbook shipped with the extension: safety rules, what each layer means for MicroProfile Fault Tolerance, how to observe an experiment including a circuit breaker’s state through theft_*metrics, the experiment loop and the report; the Agent playbook page includes the same text, with aRESILIENCE.mdtemplate for the application’s own promises.quarkus-goblin_resilienceInventorylists, indexed at build time, every application method guarded by@Timeout,@Retry,@CircuitBreaker,@Fallback,@Bulkheador@RateLimit, with the effective parameters and the Goblin layers that reach it inside Fault Tolerance. The post-assault assertions (#50) were dropped in favour of this: Goblin provides the signals, the agent or the human concludes.
Bug Fixes
-
Deactivating chaos from the Dev UI (master toggle,
Disable allkill switch,setActive(false)through JSON-RPC) is no longer undone by the next dev-mode live reload: a deactivation now survives the file save that follows it, and an explicit activation survives the next reload too. Like the auto-off, the decision belongs to the dev session and is kept in a JVM-wide system property, deliberately outside.goblin-state.json, so a new process still takes the active flag fromquarkus.goblin.enabled. A test application started by continuous testing keeps its own decision. -
The HTTP status and dependency degradation assaults no longer answer a plain-text body declared as
application/json: the abort now carries an explicit content type matching the resource contract —application/jsonwith a parseable{"message":"…","code":<status>}body on JSON resources (a JSON@Produces, or no@Producesand a POJO, collection or map return type),text/plainwith the raw message otherwise (#69). Clients switching on the 503 content type may observetext/plainwhere they previously (incorrectly) sawapplication/json.
0.3.x
| Version | Date |
|---|---|
0.3.1 |
2026-09-28 |
0.3.0 |
2026-09-25 |
0.3.1
Improvements
-
The auto-off is held by the engine instead of the browser: chaos switches itself off at the deadline even when the Dev UI is closed, and a pending auto-off survives a dev-mode live reload. The delay is bounded to 24 hours, and deactivating chaos (master toggle or kill switch) cancels it, while a configuration reset leaves it pending.
-
New JSON-RPC methods
startAutoOff(minutes)andcancelAutoOff();getStatusexposes the time left inautoOffRemainingMs. -
A profile other than
NONEalso turns the response body assault off and resets the messages of the assaults it enables (INTERMITTENTanswersInternal Server Error (Goblin chaos)). The client-side assaults and the armed layers stay untouched.
Bug Fixes
-
An application producing an anonymous, local or non-static inner class (for example a
MeterFilterreturned by a producer method) no longer fails to start: the SERVICE layer only weaves its binding onto classes that can be CDI beans, and never onto constructors. -
DATABASEexceptions no longer corrupt the Agroal pool: the fault now fires before a connection is checked out, instead of from the acquire interceptor, which left the connection enlisted in the transaction while back in the pool ("Closing connection in incorrect state CHECKED_IN", ever-growingagroal_active_count). -
A request whose entry point sits in an
exclude-packagespackage is no longer assaulted on theSERVICE,DATABASE,MESSAGINGorHTTP_OUTlayers: the layer used to be resolved before the targeting rules were checked. -
Once the auto-off has fired, chaos stays off across live reloads until it is switched on again, and clicking the master toggle just as the deadline elapses no longer switches chaos back on.
-
A test application started by continuous testing keeps its own auto-off instead of sharing the one of the dev-mode application.
-
The Dev UI dashboard survives transport errors and out-of-order status replies, and always reports an auto-disable.
0.3.0
New Features
-
Multi-layer chaos assaults with per-request layer resolution (
DATABASE→MESSAGING→SERVICE→HTTP_IN,HTTP_OUTrolled per outgoing call), one check-box per layer in the Dev UI, and service-layer assaults on business beans via a CDI interceptor that runs inside the Fault Tolerance machinery — so@Retry,@Fallback,@Timeoutand@CircuitBreakerare exercised for real. TheDATABASElayer fails or delays JDBC connection acquisition through an Agroal pool interceptor (JDBC, Hibernate ORM, Panache); theMESSAGINGlayer faults@Incomingconsumers outside Fault Tolerance, each consumed message resolving its own layer (#54). -
The
sourceof each recorded assault, already tagged in the metrics and traces since 0.2.1 (server,rest-client,webclient), gains theservice,databaseandmessagingvalues, and is now also exposed in the history, the counters and the Markdown report; the Dev UI status bar counts the assaults per source. -
The Markdown report describes the armed chaos layers and the client-side assaults.
Breaking changes
-
Chaos no longer activates in test mode by default: set
quarkus.goblin.test.enabled=trueto assault your@QuarkusTestsuite (or callAssaultEngine.setActive(true)from a test). Adding the extension therefore never slows down nor breaks an existing test suite. -
The
quarkus-goblin-metricsmodule now depends on the Micrometer API only (quarkus-micrometer): add the registry of your choice, e.g.quarkus-micrometer-registry-prometheus, to expose/q/metrics. -
Java API: the targeting rules moved from
GoblinConfig.TargetConfigtoGoblinTargetingConfig(the property names are unchanged), andAssaultEngine.setStaticConfigis removed.
Improvements
-
Every configuration key except the
quarkus.goblin.target.include-packages/exclude-packages/exclude-annotationstargeting rules is now read at runtime and can be overridden when the application starts. The targeting rules stay fixed at build time and are applied by a single implementation shared by every layer. -
No chaos wiring in production builds: the service and messaging interceptor bindings, the database hook and the Dev UI JSON-RPC are only registered in dev and test.
-
Configuration changes (profile switch, reset, import) are published atomically, and each assault hook reads one consistent snapshot per request. A Dev UI import is staged and applied at once: a rejected payload changes nothing, and values of the wrong type are converted or skipped with a warning.
-
The assault history records the latency actually endured, including a delay cut short by
@Timeout, on every layer. -
A blocking latency is never applied on a Vert.x event-loop thread (the WebClient latency uses a timer), and latency values are bounded to 0-300000 ms.
-
The Dev UI keeps its toggles and forms in sync with the server (changes made from another tab or a JSON-RPC client appear within 2 seconds) and validates response header names before saving.
-
The Dev UI state file is written as structured JSON; files written by earlier versions are still read.
-
Quarkus 3.38 and every later version are accepted by the build (including the ecosystem CI snapshot).
Bug Fixes
-
A decision left on a worker thread by a failed HTTP request no longer leaks into a later message consumer or scheduled job.
-
The Dev UI "client" counter counted nothing: assaults are now counted per source.
-
Saving response header rules with an invalid name no longer erases every rule.
-
A corrupted or legacy
.goblin-state.jsonno longer prevents the application from starting.
0.2.x
| Version | Date |
|---|---|
0.2.1 |
2026-09-24 |
0.2.0 |
2026-09-21 |
0.2.1
New Features
-
Assault metrics and latency histograms via Micrometer / Prometheus, in the optional
quarkus-goblin-metricsmodule (#51). -
Assault tracing via OpenTelemetry — one
goblin.assaultspan per assault withgoblin.assault.*attributes, linked to the parent request span, in the optionalquarkus-goblin-opentelemetrymodule (#47).
0.2.0
New Features
-
Predefined assault profiles (#35).
-
Turn the Assault History into a chaos testing console (#37).
-
Client-side assaults for outgoing REST Client calls (#38).
-
Client-side assaults for outgoing Vert.x WebClient calls via
GoblinWebClient.enable(…)(#31). -
Response body injection assault (#40).
-
Response header injection assault (#42).
Improvements
-
Chaos Dashboard overhaul with live controls and server-driven quick picks (#41).
Bug Fixes
-
The enabled flag now always comes from the property, never from persisted state (#39).
0.0.x
| Version | Date |
|---|---|
0.0.2 |
2026-09-01 |
0.0.1 |
2026-08-28 |
0.0.1
New Features
-
Server-side assaults: latency, exception, HTTP status and dependency degradation (#1).