Skip to content

ACID: Redis events and work queues are not tied to DB commits (no outbox) #54

Description

@Atsilut

Structure

Post-commit side effectsIEventPublisher and IWorkQueue enqueue after Postgres commit with no transactional guarantee.

Problem

If the process crashes or Redis fails between DB commit and enqueue/publish, the system is inconsistent:

Flow DB state Side effect lost
ChatMessageService.CreateMessageAsync Message persisted Stream job, pub/sub event, SignalR
MediaService.CompleteUploadAsync Status Processing media.uploaded worker job
UserService.DeleteUserAsync / nickname update User updated/deleted UserNicknameChanged event, cache invalidate

RedisStreamWorkQueue.EnqueueAsync and RedisEventPublisher.PublishAsync are separate from EF transactions (services/Tangle.AspNetCore/Queue/, services/Users/Infrastructure/RedisEventPublisher.cs).

Workers use at-least-once delivery (ack after handler success) — correct for async work, but does not fix lost enqueues.

Suggested fix

Introduce a transactional outbox pattern (per service or shared in Tangle.AspNetCore):

  1. Write outbox row in same DB transaction as domain change.
  2. Background dispatcher reads outbox → Redis Streams / pub/sub.
  3. Idempotent consumers keyed by messageId / mediaAssetId.

Phased rollout: start with media.uploaded and chat.message.created (highest business impact).

Acceptance criteria

  • Design doc for outbox table schema and dispatcher
  • At least one critical path (media complete or chat message) uses outbox
  • Dispatcher retry + dead-letter for failed publishes
  • Update docs/QUEUE.md and docs/EVENTS.md with durability guarantees

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions