Skip to content

feat(trading): add transactional domain event outbox#116

Merged
blackms merged 9 commits into
mainfrom
codex/order-fill-outbox
Apr 26, 2026
Merged

feat(trading): add transactional domain event outbox#116
blackms merged 9 commits into
mainfrom
codex/order-fill-outbox

Conversation

@blackms

@blackms blackms commented Apr 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Persists trading domain events in a JSON-backed transactional outbox before order/position/portfolio commits complete.
  • Routes open, close, DCA, and refresh fill events through the outbox, then dispatches and marks them processed after successful commit.
  • Adds rollback/idempotency coverage for the outbox and keeps the existing post-commit event dispatcher behavior.

Acceptance Criteria

  • Given an order fill is applied by a trading handler, when aggregate state is committed, then the related domain events are enqueued in the outbox before commit.
  • Given the JSON unit of work commits order state and outbox state, when another enlisted resource fails, then neither the order-side event nor the failed aggregate state is persisted.
  • Given an outbox event has already been marked processed, when it is marked processed again, then its processed timestamp is not changed.

Changes

  • Added IDomainEventOutbox and DomainEventOutboxMessage as application ports.
  • Added JsonDomainEventOutbox and Autofac registration using the existing JSON transaction coordinator.
  • Updated trading handlers to collect events, enqueue them transactionally, dispatch post-commit, and mark events processed.
  • Centralized handler event workflow in DomainEventOutboxWorkflow.

Testing

  • Added/updated application handler tests for refresh, open, DCA, and close event outbox behavior.
  • Added infrastructure integration tests for outbox commit, rollback, and idempotent processing.
  • Verified with dotnet test IntelliTrader.sln --configuration Release --no-restore --no-build.
  • Verified whitespace with git diff --check.

Checklist

  • Tests pass
  • Coverage maintained for the changed paths
  • Linter/whitespace clean
  • Documentation not required; no user-facing behavior change

Summary by CodeRabbit

  • New Features

    • Implemented a durable event persistence system for trading operations to ensure transaction events survive system failures and are properly recovered.
    • Enhanced trading workflow handlers to reliably queue events during transaction processing before finalizing operations.
  • Tests

    • Added comprehensive integration and unit test coverage for event persistence, failure handling, and event recovery scenarios.

@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 a durable domain-event outbox pattern with a new IDomainEventOutbox interface and DomainEventOutboxMessage record. Four trading handlers are refactored to collect domain events, enqueue them to the outbox during persistence, clear aggregate events, and dispatch only after commit via a new DomainEventOutboxWorkflow helper. A JsonDomainEventOutbox implementation persists events to JSON files with transaction support.

Changes

Cohort / File(s) Summary
Core Outbox Abstraction
IntelliTrader.Application/Ports/Driven/IDomainEventOutbox.cs
Defines IDomainEventOutbox interface with EnqueueAsync, GetUnprocessedAsync, and MarkProcessedAsync methods. Introduces DomainEventOutboxMessage record with event metadata and derived IsProcessed property.
Outbox Workflow Helper
IntelliTrader.Application/Trading/Handlers/DomainEventOutboxWorkflow.cs
New internal helper class providing Collect and Clear overloads for trading aggregates, EnqueueAsync for persistence, and DispatchCommittedAsync for post-commit event dispatch with error handling and outbox mark-processed operations.
Outbox Implementation
IntelliTrader.Infrastructure/Adapters/Persistence/Json/JsonDomainEventOutbox.cs
Concrete JSON-file-based outbox implementation with in-memory ConcurrentDictionary caching, semaphore-based file locking, lazy loading, and integration with JsonTransactionCoordinator for transactional reads/writes; implements IJsonTransactionalResource for commit/prepare/rollback.
Trading Handler Refactors
IntelliTrader.Application/Trading/Handlers/ClosePositionHandler.cs, ExecuteDCAHandler.cs, OpenPositionHandler.cs, RefreshOrderStatusHandler.cs
Each handler updated to inject IDomainEventOutbox, collect domain events from aggregates, enqueue events to outbox within transaction before commit, clear aggregate events, and dispatch via DomainEventOutboxWorkflow.DispatchCommittedAsync after commit. Direct dispatch helpers removed.
Container Registration
IntelliTrader.Infrastructure/AppModule.cs
Registers JsonDomainEventOutbox singleton with configured file path outbox.json and JsonTransactionCoordinator, exposing via IDomainEventOutbox abstraction.
Handler Test Updates
tests/IntelliTrader.Application.Tests/Trading/Handlers/ClosePositionHandlerTests.cs, ExecuteDCAHandlerTests.cs, OpenPositionHandlerTests.cs, RefreshOrderStatusHandlerTests.cs
Each test fixture updated to inject IDomainEventOutbox mock into handler construction and verify outbox enqueue and mark-processed behavior alongside dispatcher assertions.
Integration Tests
tests/IntelliTrader.Infrastructure.Tests/Integration/JsonTransactionalUnitOfWorkIntegrationTests.cs
Three new scenarios verify outbox event persistence on successful commit, rollback on upstream failure, and idempotent mark-processed behavior; includes helper methods for test setup and cleanup.

Sequence Diagram(s)

sequenceDiagram
    participant Handler as Trading Handler
    participant Aggregate as Order/Position<br/>Aggregate
    participant Outbox as IDomainEventOutbox
    participant UoW as TransactionalUnitOfWork
    participant Dispatcher as IDomainEventDispatcher

    Handler->>Aggregate: Execute domain operation
    Aggregate-->>Handler: Generate domain events
    Handler->>Handler: Collect events from aggregates
    Handler->>Outbox: EnqueueAsync(events)
    Outbox-->>Handler: Events queued (not yet persisted)
    Handler->>Aggregate: Clear domain events
    Handler->>UoW: CommitAsync()
    UoW->>Outbox: Persist queued events to storage
    UoW-->>Handler: Commit confirmed
    Handler->>Dispatcher: DispatchManyAsync(events)
    Dispatcher-->>Handler: Events dispatched to subscribers
    Handler->>Outbox: MarkProcessedAsync(eventId)
    Outbox-->>Handler: Event marked as processed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • feat(cqrs): harden active order refresh #115: Modifies the same four trading handler implementations (ClosePositionHandler, ExecuteDCAHandler, OpenPositionHandler, RefreshOrderStatusHandler) and their transactional/persistence flows, with direct code-level overlap in handler refactoring patterns.

Poem

🐰 Hark! Events now find their way,
To the outbox, where they stay,
Enqueued safely, marked with care,
Then dispatched with flair!
A rabbit's pattern, tried and true. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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(trading): add transactional domain event outbox' clearly and concisely summarizes the primary change: the addition of a transactional outbox for domain events in the trading module.
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/order-fill-outbox

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 87.72563% with 34 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...Adapters/Persistence/Json/JsonDomainEventOutbox.cs 82.11% 13 Missing and 14 partials ⚠️
...der.Application/Ports/Driven/IDomainEventOutbox.cs 62.50% 3 Missing ⚠️
...plication/Trading/Handlers/ClosePositionHandler.cs 96.15% 0 Missing and 1 partial ⚠️
....Application/Trading/Handlers/ExecuteDCAHandler.cs 94.44% 0 Missing and 1 partial ⚠️
...pplication/Trading/Handlers/OpenPositionHandler.cs 94.44% 0 Missing and 1 partial ⚠️
...tion/Trading/Handlers/RefreshOrderStatusHandler.cs 94.44% 0 Missing and 1 partial ⚠️
Files with missing lines Coverage Δ
...tion/Trading/Handlers/DomainEventOutboxWorkflow.cs 100.00% <100.00%> (ø)
IntelliTrader.Infrastructure/AppModule.cs 92.98% <100.00%> (+0.32%) ⬆️
...plication/Trading/Handlers/ClosePositionHandler.cs 85.95% <96.15%> (+0.17%) ⬆️
....Application/Trading/Handlers/ExecuteDCAHandler.cs 86.73% <94.44%> (-0.32%) ⬇️
...pplication/Trading/Handlers/OpenPositionHandler.cs 84.52% <94.44%> (-0.33%) ⬇️
...tion/Trading/Handlers/RefreshOrderStatusHandler.cs 91.22% <94.44%> (+0.47%) ⬆️
...der.Application/Ports/Driven/IDomainEventOutbox.cs 62.50% <62.50%> (ø)
...Adapters/Persistence/Json/JsonDomainEventOutbox.cs 82.11% <82.11%> (ø)

... and 8 files 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 marked this pull request as ready for review April 26, 2026 18:07
@blackms blackms merged commit ce152dc into main Apr 26, 2026
2 of 3 checks passed
@blackms blackms deleted the codex/order-fill-outbox branch April 26, 2026 18:11
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