fix: the api jar did not start, and nothing in the build noticed - #65
Merged
Conversation
Two failures, one release. Both were found by the cluster rather than by the build, which is the part worth fixing. ## The api would not start TenantGroupIndexLoader declared @scheduled(fixedDelay = "60s"). Micronaut's converter rejects that spelling, and because the scheduled-method processor runs during context start, it did not fail one bean -- it failed the application. The single api replica went into CrashLoopBackOff and took the whole API down for about eight minutes, until the platform chart was rolled back to 0.8.0. It now schedules through TaskScheduler with a typed Duration. A constant cannot be spelled wrong, and if it could, the compiler would say so instead of the kubelet. ## Nothing in the build could have caught it This took two attempts to establish honestly. A test that boots a real Micronaut context with an embedded server passed with the bug faithfully reintroduced -- so that "guard" was worthless. The difference is not the environment, it is the shadowed jar: on the plain test classpath "60s" converts fine. So :api:startupSmokeTest boots the shadowed jar and fails if the context does not start, and it is wired into check. Verified in both directions -- green on the fix, red on the reintroduced bug, with the real error in the failure message. ApplicationStartupTest stays for what it does catch, with its Javadoc corrected to say plainly that this is not it. ## The operator could not read Rook's own resource Separately, and not new: CephObjectStoreUserStatus modelled only `phase`, while Rook had added `status.info` and `status.observedGeneration`. TenantReconciler reads the existing user before touching it, so every reconciliation of every tenant threw UnrecognizedPropertyException and exhausted its retries. Nothing looked broken -- a tenant only reconciles when something changes -- until this release needed one, and then the tenant silently never got its application instance. All four Rook model types now ignore unmodelled fields. The fix is deliberately not "add info": that is a race against another project's roadmap. A model of somebody else's resource must not fail on a field it never reads. The test uses the verbatim JSON from the live cluster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Bff5mpWkUnZA77jys8DiR
Contributor
Test results675 tests 675 ✅ 2m 3s ⏱️ Results for commit 3bae1f6. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two failures, one release. Both were found by the cluster rather than by the build, which is the part worth fixing.
The api would not start
TenantGroupIndexLoaderdeclared@Scheduled(fixedDelay = "60s"). Micronaut's converter rejects that spelling, and because the scheduled-method processor runs during contextstart(), it did not fail one bean — it failed the application:0.9.0 was published, rolled out, and the single
apireplica went into CrashLoopBackOff — the whole API was down for about eight minutes, until the platform chart was rolled back to 0.8.0 (Kubernetes-FLUX#177).It now schedules through
TaskSchedulerwith a typedDuration. A constant cannot be spelled wrong, and if it could, the compiler would say so instead of the kubelet.Nothing in the build could have caught it
This took two attempts to establish honestly, and the first attempt is worth reporting.
I added a test that boots a real Micronaut context with an embedded server, on the theory that it would have caught this. Then I reintroduced the bug — faithfully,
public final void refresh()and all — and the test passed. The difference is not the environment. It is the shadowed jar: on the plain test classpath"60s"converts fine, and no@MicronautTestcan see the failure.So
:api:startupSmokeTestboots the shadowed jar and fails if the context does not start, wired intocheck. Verified in both directions — green on the fix, red on the reintroduced bug, with the real error in the failure message:ApplicationStartupTeststays for what it does catch (unsatisfiable beans, factories that throw, properties that will not bind), with its Javadoc corrected to say plainly that this is not it.The operator could not read Rook's own resource
Separately, and not introduced by 0.9.0:
CephObjectStoreUserStatusmodelled onlyphase, while Rook had addedstatus.infoandstatus.observedGeneration.TenantReconcilerreads the existing user before touching it, so every reconciliation of every tenant threwUnrecognizedPropertyException: Unrecognized field "info"and exhausted its retries.Nothing looked broken — a tenant only reconciles when something changes — until this release needed one. Then the tenant silently never got its application instance, which is how it was found.
All four Rook model types now ignore unmodelled fields. The fix is deliberately not to add
info: that is a race against another project's roadmap. A model of somebody else's resource must not fail on a field it never reads. The test uses the verbatim JSON from the live cluster.Verification
:api:check:operator:testspotlessCheckAfter merge
Release 0.9.1, then bring the
apus-platformpin in Kubernetes-FLUX back from=0.8.0to=0.9.1. The comment at that pin says so and names the condition.🤖 Generated with Claude Code
https://claude.ai/code/session_019Bff5mpWkUnZA77jys8DiR