Skip to content

feat(outbox): replay pending domain events#117

Merged
blackms merged 8 commits into
mainfrom
codex/outbox-processor
Apr 26, 2026
Merged

feat(outbox): replay pending domain events#117
blackms merged 8 commits into
mainfrom
codex/outbox-processor

Conversation

@blackms

@blackms blackms commented Apr 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds a durable outbox processor that replays pending domain events after post-commit dispatch failures.
  • Keeps failed replay messages pending and reports attempted/processed/failed counts for retryable processing.
  • Starts scheduled outbox replay with the trading runtime through a Core lifecycle service.

Acceptance Criteria

  • Given an unprocessed outbox message, when the outbox processor runs, then the event is deserialized, dispatched, and marked processed.
  • Given dispatch fails for a pending outbox message, when the processor runs, then the event remains pending and the failure is reported without throwing.
  • Given the scheduled outbox service runs, when a cycle executes, then it calls the processor with the configured batch size.
  • Given trading runtime is enabled, when CoreService starts and stops, then outbox replay starts and stops with the trading services.

Changes

  • Added IDomainEventOutboxProcessor and DomainEventOutboxProcessingResult application port.
  • Added DomainEventOutboxProcessor for pending message replay and per-message failure isolation.
  • Added scheduled DomainEventOutboxProcessorService and Core-facing DomainEventOutboxReplayService.
  • Registered outbox processor/replay services in Autofac and wired replay lifecycle into CoreService.
  • Added RED/GREEN tests for replay success, retryable failures, scheduled processing, and Core lifecycle wiring.

Testing

  • dotnet test tests/IntelliTrader.Infrastructure.Tests/IntelliTrader.Infrastructure.Tests.csproj --no-restore --filter "FullyQualifiedName~DomainEventOutboxProcessorTests|FullyQualifiedName~DomainEventOutboxProcessorServiceTests"
  • dotnet test tests/IntelliTrader.Core.Tests/IntelliTrader.Core.Tests.csproj --no-restore --filter "FullyQualifiedName~DomainEventOutboxReplayService|FullyQualifiedName~ActiveOrderRefreshService"
  • dotnet test IntelliTrader.sln --configuration Release --no-restore
  • git diff --check

Checklist

  • Tests pass
  • Coverage maintained with new unit/integration tests
  • Linter/whitespace clean
  • Documentation not needed; internal runtime behavior only

Summary by CodeRabbit

  • New Features
    • Introduced a durable domain event outbox with automatic background replay of unprocessed events, ensuring reliable event delivery with configurable batch processing and retry behavior.
    • Integrated outbox replay service with application startup and shutdown lifecycle for seamless operations.

@coderabbitai

coderabbitai Bot commented Apr 26, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Introduces durable domain event outbox processing infrastructure. Adds IDomainEventOutboxProcessor interface with batch processing capability, DomainEventOutboxProcessor implementation for deserializing and dispatching pending events, DomainEventOutboxReplayService for lifecycle management, and integrates replay service into CoreService startup/shutdown cycles.

Changes

Cohort / File(s) Summary
Outbox Processing Contracts
IntelliTrader.Application/Ports/Driven/IDomainEventOutboxProcessor.cs
Defines IDomainEventOutboxProcessor interface with ProcessPendingAsync method and DomainEventOutboxProcessingResult record capturing attempted, processed, and failed event counts.
Outbox Processor Implementation
IntelliTrader.Infrastructure/Events/DomainEventOutboxProcessor.cs
Implements batch processing of pending outbox events: retrieves unprocessed messages, deserializes payloads using camelCase JSON, validates CLR types, dispatches via IDomainEventDispatcher, and marks successful messages as processed while catching and logging failures.
Background Service Infrastructure
IntelliTrader.Infrastructure/BackgroundServices/DomainEventOutboxProcessorService.cs, IntelliTrader.Infrastructure/BackgroundServices/DomainEventOutboxReplayService.cs
Adds DomainEventOutboxProcessorService as timed background service wrapper with configurable Interval, StartDelay, and BatchSize. Adds DomainEventOutboxReplayService as lifecycle manager implementing IDomainEventOutboxReplayService with Start()/Stop() methods for background replay control.
Lifecycle Management
IntelliTrader.Core/Interfaces/Services/IDomainEventOutboxReplayService.cs, IntelliTrader.Core/Services/CoreService.cs
Defines IDomainEventOutboxReplayService interface. Integrates replay service into CoreService to start/stop outbox processing alongside trading lifecycle when enabled.
Service Registration
IntelliTrader.Infrastructure/AppModule.cs
Registers DomainEventOutboxProcessor, DomainEventOutboxProcessorService, and DomainEventOutboxReplayService as singletons with required dependencies including IDomainEventOutbox and IDomainEventDispatcher.
Test Coverage
tests/IntelliTrader.Core.Tests/CoreService*.cs, tests/IntelliTrader.Infrastructure.Tests/BackgroundServices/DomainEventOutboxProcessorServiceTests.cs, tests/IntelliTrader.Infrastructure.Tests/Events/DomainEventOutboxProcessorTests.cs
Extends CoreServiceTests to verify replay service Start()/Stop() calls during trading lifecycle. Adds DomainEventOutboxProcessorServiceTests verifying batch size configuration. Adds DomainEventOutboxProcessorTests with happy-path and failure scenarios using file-backed outbox.

Sequence Diagram(s)

sequenceDiagram
    participant Core as CoreService
    participant Replay as DomainEventOutboxReplayService
    participant Background as DomainEventOutboxProcessorService
    participant Processor as DomainEventOutboxProcessor
    participant Outbox as IDomainEventOutbox
    participant Dispatcher as IDomainEventDispatcher

    Core->>Replay: Start()
    activate Replay
    Replay->>Background: new + Start()
    activate Background
    Background->>Background: TimedBackgroundService timer
    Background->>Processor: ProcessPendingAsync(batchSize, token)
    activate Processor
    Processor->>Outbox: GetUnprocessedAsync(batchSize)
    Outbox-->>Processor: List<DomainEventOutboxMessage>
    loop For Each Message
        Processor->>Processor: Deserialize & Validate
        Processor->>Dispatcher: DispatchAsync(event)
        Dispatcher-->>Processor: Success
        Processor->>Outbox: MarkAsProcessedAsync(messageId)
    end
    Processor-->>Background: DomainEventOutboxProcessingResult
    deactivate Processor
    Background-->>Replay: (scheduled execution)
    deactivate Background

    Core->>Replay: Stop()
    Replay->>Background: Stop()
    activate Background
    Background->>Background: Cancel token & dispose
    deactivate Background
    deactivate Replay
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hops with glee through outbox queues,
Events replay, no pending dues,
Batch by batch, the processor hops,
Durable replay never stops! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(outbox): replay pending domain events' accurately reflects the main objective of the changeset, which introduces infrastructure for replaying pending domain events from a durable outbox.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/outbox-processor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Apr 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 54.61538% with 59 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ckgroundServices/DomainEventOutboxReplayService.cs 0.00% 32 Missing ⚠️
...nfrastructure/Events/DomainEventOutboxProcessor.cs 76.78% 7 Missing and 6 partials ⚠️
IntelliTrader.Infrastructure/AppModule.cs 58.82% 7 Missing ⚠️
...roundServices/DomainEventOutboxProcessorService.cs 63.15% 2 Missing and 5 partials ⚠️
Files with missing lines Coverage Δ
...cation/Ports/Driven/IDomainEventOutboxProcessor.cs 100.00% <100.00%> (ø)
IntelliTrader.Core/Services/CoreService.cs 56.58% <100.00%> (+0.68%) ⬆️
IntelliTrader.Infrastructure/AppModule.cs 88.54% <58.82%> (-4.44%) ⬇️
...roundServices/DomainEventOutboxProcessorService.cs 63.15% <63.15%> (ø)
...nfrastructure/Events/DomainEventOutboxProcessor.cs 76.78% <76.78%> (ø)
...ckgroundServices/DomainEventOutboxReplayService.cs 0.00% <0.00%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@blackms blackms merged commit e07ee2e into main Apr 26, 2026
2 of 3 checks passed
@blackms blackms deleted the codex/outbox-processor branch April 26, 2026 19:47
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