Fix the Oracle queue Uri identity round-trip, and finish GH-3808 (GH-3820) - #3823
Merged
Conversation
…3820) OracleTransport.findEndpointByUri looked its queue up with a bare Queues[uri.Host]. That is correct for the Postgres and SQL Server transports it was copied from, whose SanitizeIdentifier lower-cases -- matching how System.Uri normalises the authority. Oracle's SanitizeIdentifier upper-cases, so uri.Host never matched the key the queue was registered under and LightweightCache quietly minted a SECOND OracleQueue over the same physical queue tables. Oracle is the only transport in the repo that upper-cases identifiers, so it is the only one affected. This is a product bug, not a test quirk: any ToOracleQueue("name") subscription resolves through this path, because the publishing.To(queue.Uri) inside it round-trips the endpoint through its own Uri. Fixed by correcting the name on the way back in. SanitizeIdentifier rather than MaybeCorrectName deliberately -- the host segment already carries any IdentifierPrefix, which MaybeCorrectName would prepend a second time. The correction is idempotent, so a Uri built from an already-corrected name is unaffected. Covered by two tests that need no database and fail on main. With that fixed, the clear_all_wolverine_storage compliance class no longer needs the listener it only ever attached to work around the duplicate endpoint, so it goes subscriber-only like Postgres, SQL Server, MySql and Sqlite. The listener was also the only thing holding a TM/DML lock on the queue table, which is what made the ORA-00054 in beforeHostAsync reachable once GH-3808 pointed the DROP at a schema whose tables actually exist. Also fixes the unreachable failure handler introduced in GH-3808: the `when (e.Number == 54 && attempt < maxAttempts)` guard was false on the final attempt, so the raw OracleException escaped the loop and the descriptive InvalidOperationException below it was dead code that never ran once. ORA-54 is now caught unconditionally and the last one is carried out as the inner exception. Full OracleTests suite: 115 passed, 0 failed. The clear_all class now runs 7 tests in 6s with no retry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WHAuhdWS3XeAk16swV9G8m
This was referenced Aug 5, 2026
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.
Closes #3820.
The handoff called the casing mismatch under #3808 "the real bug to chase." It is — and it is a
product bug, not a test quirk. It reproduces in 43ms with no Oracle container.
The defect
OracleTransport.findEndpointByUrilooked its queue up with a bareQueues[uri.Host]:That is correct for the two transports it was copied from — and wrong for this one:
SanitizeIdentifierSystem.UriauthorityToLowerInvariantToLowerInvariantToUpperInvariantSystem.Urinormalises the authority to lower case, so an upper-cased Oracle queue name never cameback out of its own Uri.
Queuesis aLightweightCache, so the miss didn't throw — it silentlycreated a second
OracleQueueover the same physical queue tables.This is reachable from ordinary user code:
ToOracleQueue("name")ends withpublishing.To(queue.Uri), which round-trips the endpoint through its own Uri. Oracle is the onlytransport in the repo whose
SanitizeIdentifierupper-cases, so it is the only one affected —checked across every
SanitizeIdentifieroverride.The fix
Queues[SanitizeIdentifier(uri.Host)].SanitizeIdentifierrather thanMaybeCorrectNamedeliberately: the host segment already carries any
IdentifierPrefix, whichMaybeCorrectNamewouldprepend a second time. The correction is idempotent, so a Uri built from an already-corrected name is
unaffected.
Two new tests, no database required, both red on
main:The other two
uri.Hostreads in the Oracle transport areGuid.Parseon control-endpoint node ids,which is case-insensitive — not affected.
What that unlocks
clear_all_wolverine_storagewas the sole provider inClearAllWolverineStorageComplianceattachinga listener, against the base class's explicit instruction, purely to work around the duplicate
endpoint. It can now go subscriber-only like Postgres, SQL Server, MySql and Sqlite.
That also removes the cause of the ORA-00054 the handoff flagged. The listener was the only thing
holding a TM/DML lock on the queue table; #3808 made that lock reachable by pointing the DROP at a
schema whose tables actually exist. So the contention is gone rather than retried around.
The unreachable handler (my defect from #3808)
On the final attempt the guard is false, the raw
OracleExceptionescapes the loop, and thedescriptive
InvalidOperationExceptionbelow it is dead code — it never ran once, which is exactlywhat the CI error demonstrated. ORA-54 is now caught unconditionally, with the last one carried out as
the inner exception so the descriptive throw finally names the underlying Oracle error too.
The retry itself stays as a belt-and-braces guard — a host from a prior class in the collection can
still be tearing connections down — and the doc comment no longer claims a listener this class no
longer has.
Verification
OracleTestssuite: 115 passed, 0 failed (against a livegvenzl/oracle-free:23-slim)clear_all_wolverine_storage+ the new tests: 7 passed in 6s, no retry (was 1 retry/run)wolverine.slnxRelease build clean, 0 warnings🤖 Generated with Claude Code
https://claude.ai/code/session_01WHAuhdWS3XeAk16swV9G8m