Skip to content

[messages] extract state transitions - #424

Open
capcom6 wants to merge 1 commit into
masterfrom
messages/unified-message-state-service
Open

capcom6 wants to merge 1 commit into
masterfrom
messages/unified-message-state-service

Conversation

@capcom6

@capcom6 capcom6 commented Aug 16, 2026 •

Copy link
Copy Markdown
Owner

"## Purpose\n\nExtract message and recipient state transitions from MessagesService into a dedicated MessageStateService -- the single point of control for all message state operations. Centralizes transition validation, persistence, and event emission, and fixes a cancellation race condition where a concurrent send worker could dispatch an SMS after recipients were already marked Cancelled.\n\n## Key Changes\n\n### New files\n- MessageStateService.kt -- Single owner of state-transition logic. Every transition: acquires per-message lock, loads current row, validates against MessageStateTransitions, applies the DAO write, syncs stored state from derived recipient state, and emits MessageStateChangedEvent only on successful writes.\n- MessageStateTransitions.kt -- Pure state-machine table. Cancelled is not terminal (late SMS outcomes supersede cancel). Failed is the only terminal state.\n- PerMessageLock.kt -- Per-key mutex with atomic reference-counted entry lifecycle. Same-key blocks serialize; different keys run in parallel.\n\n### Modified files\n- MessagesDao.kt -- Added updateRecipientsAndMessageState: a single DB transaction that atomically updates recipient and message state, eliminating the two-transaction race window.\n- MessagesService.kt -- Removed ~86 lines of inline state logic; delegates to MessageStateService.\n- GatewayApi.kt -- Added Cancelling to wire-level MessageState, explicitly separated from local ProcessingState.\n- GatewayService.kt -- Resolves cloud Cancelling via the extracted local cancellation path (handleCloudCancel).\n- EventsReceiver.kt -- Handles MessageCancelledEvent by delegating to MessagesService.cancelMessage.\n\n### New tests\n- MessageStateServiceTest.kt -- State-machine validation, cancellation strict-reject, and event emission.\n- MessageStateTransitionsTest.kt -- Transition table correctness.\n- PerMessageLockTest.kt -- Concurrency serialization and entry lifecycle.\n- CancelEntryPointsParityTest.kt -- Parity across all cancellation entry points.\n- GatewayWireStateTest.kt -- Cancelling wire state resolution.\n\n## Cancellation Race Condition Fix\n\nPreviously, cancellation committed recipient and message state in separate transactions. A concurrent send worker could observe Pending between commits and dispatch the SMS. The fix: updateRecipientsAndMessageState atomically updates both in one transaction, and PerMessageLock serializes the full read-validate-write-sync-emit cycle per message.\n\n## Known Limitations\n\n- The send worker's pre-send state check in sendMessage remains outside the lock. Atomic updateRecipientsAndMessageState eliminates the race; the unlocked check is defense-in-depth.\n- DAO mutation methods remain public; visibility cleanup is deferred.\n"

RetriggerConfidence Score: 5/5

The PR appears safe to merge.

Summary

The PR centralizes message and recipient state transitions behind a per-message lock and separates the gateway’s wire-level cancellation state from local processing states.

  • Adds validated, serialized state transitions with atomic recipient/message persistence and event emission.
  • Routes cancellation entry points and send-result handling through the new state service.
  • Adds concurrency, transition-table, cancellation-parity, and gateway wire-state tests.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[State transition request] --> B[Acquire per-message lock]
    B --> C[Load message and recipients]
    C --> D{Transition valid?}
    D -- No --> E[Reject or no-op]
    D -- Yes --> F[Atomically persist recipient and message state]
    F --> G[Reload persisted state]
    G --> H[Emit MessageStateChangedEvent]
    H --> I[Release lock]
Loading

Reviews (26) · Last reviewed commit: "[messages] introduce message state servi..."

Comment thread app/src/main/java/me/capcom/smsgateway/modules/messages/MessageStateService.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/modules/messages/PerMessageLock.kt Outdated
@github-actions

github-actions Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

🤖 Pull request artifacts

file commit
app-release.apk 487b8e3
app-release.aab 487b8e3
app-insecure.apk 487b8e3
app-insecure.aab 487b8e3

Comment thread app/src/main/java/me/capcom/smsgateway/modules/messages/PerMessageLock.kt Outdated
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch 3 times, most recently from ee18a96 to e87837a Compare August 19, 2026 07:55
@capcom6 capcom6 added the ready label Aug 19, 2026
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from e87837a to 0253ec7 Compare August 20, 2026 00:49
@github-actions github-actions Bot removed the ready label Aug 20, 2026
@capcom6 capcom6 added the ready label Aug 20, 2026
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from 0253ec7 to 51430e4 Compare August 21, 2026 03:52
@github-actions github-actions Bot removed the ready label Aug 21, 2026
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from 78114a1 to c9307f8 Compare August 21, 2026 11:50
@capcom6 capcom6 added the ready label Aug 21, 2026
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from c9307f8 to e0c178c Compare August 25, 2026 01:58
@github-actions github-actions Bot removed the ready label Aug 25, 2026
@capcom6 capcom6 added the ready label Aug 25, 2026
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from e0c178c to d987662 Compare August 27, 2026 00:30
@github-actions github-actions Bot removed the ready label Aug 27, 2026
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from fe75b52 to eb8889f Compare August 29, 2026 23:31
Comment thread app/src/main/java/me/capcom/smsgateway/modules/messages/MessageStateService.kt Outdated
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from 18f55b6 to aee1110 Compare August 31, 2026 02:57
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from aee1110 to d28a4ae Compare August 31, 2026 07:28
Comment thread app/src/main/java/me/capcom/smsgateway/modules/messages/MessagesService.kt Outdated
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch 5 times, most recently from c03d0f3 to 3918c51 Compare September 8, 2026 01:16
@github-actions

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open for 7 days with no activity.

@github-actions github-actions Bot added the stale label Sep 17, 2026
@capcom6 capcom6 removed the stale label Sep 18, 2026
@capcom6
capcom6 force-pushed the messages/unified-message-state-service branch from 3918c51 to 487b8e3 Compare September 25, 2026 01:44
@github-actions github-actions Bot removed the ready label Sep 25, 2026

This branch has not been deployed

No deployments
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.

1 participant