Retry the two rights reads that stand between a password and a session

Fixkamo-shared-library
Shipped
September 5, 2026 at 6:53 PM UTC
Author
Kamo
Commit
ed8db28

MemberRightsAppliedService carried @RetryOnDbConflict on its WRITE entry points only. The class therefore read as covered while the two methods the authenticated surface actually calls stood bare, and a catalog-version bump kept reaching users through them. On 2026-09-05 it reached them at the worst possible place — the sign-in screen, which showed: Login failed: JDBC exception executing SQL [select d1_0.id,d1_0.email, d1_0.mailbox_id,o1_0.id,... from depts d1_0 left join (orgs o1_0 left join org_mtg o1_1 ...)] [ERROR: schema version mismatch for table **************** expected 160, got 158] The path is create***Id -> **************** which loads the member and then dereferences TeamMember.department. That dereference is LAZY, so it is a SELECT of its own, and it is the statement the bump lands on. It runs before the session is minted, so the whole sign-in fails rather than degrading — the member is simply told the login failed, with several hundred columns of generated SQL for company. computeMemberRights is the same story one endpoint over. SessionRefreshController polls it on a short interval for every signed-in client, which made it the most frequent victim in the same window: 12 of the 70 conflicts logged fleet-wide over six hours came through it. Both overloads of each are annotated. The by-id overloads reach the by-entity ones through self-invocation, which bypasses the proxy, so an attempt is still three attempts and not nine. Not a retry around **************** which would have covered the same failure in one line. That method mints a session, issues an MFA token, stamps last-login and publishes availability; none of that rolls back with the transaction, so running it twice is exactly what @RetryOnDbConflict's own documentation says not to do. The reads are pure, which is why the retry belongs on them. The test asserts through a real Spring proxy rather than calling the helper directly: an annotation that is present but not applied looks identical to one that is working. Removing the four annotations fails both tests with the CannotAcquireLockException from the report. 2778 tests green.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing