Skip to content

Clamp operator counter decrements at zero - #3

Merged
daniser merged 1 commit into
masterfrom
fix/clamp-operator-counter-decrements
Nov 10, 2026
Merged

daniser merged 1 commit into
masterfrom
fix/clamp-operator-counter-decrements

Conversation

@EgorGruzdev

Copy link
Copy Markdown
Contributor

Problem

ticket_allocator_operators.bound_tickets / total_complexity are unsigned. When a counter has drifted below the real number of bound tickets (e.g. an external recount raced with Triage increments), OperatorProjector decrements it below zero and MySQL throws:

SQLSTATE[22003]: 1690 BIGINT UNSIGNED value is out of range in '(`bound_tickets` - 1)'

The exception aborts the projection: TicketProjector (weight 5) never runs after OperatorProjector (weight 0), so the ticket.closed event is stored but the ticket stays alive and bound to the operator, occupying a slot.

Change

  • Operator::decrementToZero() — same flow as Model::decrement() (fires updating, so ReadonlyProjection protection is kept; touches updated_at; syncs attributes), but issues col = GREATEST(col, n) - n atomically in SQL. GREATEST(col - n, 0) would not help: col - n on unsigned zero fails before GREATEST is evaluated.
  • OperatorProjector: all decrements in onTicketBound (previous operator), onTicketUnbound, onTicketClosed use it. Increments untouched.

Verified

In the host app against local MySQL, inside a rolled-back transaction: operator with bound_tickets = 0, close its ticket.

  • before: QueryException 22003, ticket not deleted;
  • after: counters 0, ticket soft-deleted.

bound_tickets and total_complexity are unsigned; a drifted counter made
decrement() throw SQLSTATE 22003 on ticket close/unbind, which aborted
projection and left the closed ticket bound to the operator.
@daniser
daniser merged commit 5e72e67 into master Nov 10, 2026
0 of 2 checks passed
@daniser
daniser deleted the fix/clamp-operator-counter-decrements branch November 10, 2026 10:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants