Skip to content

Refactor: extract CDC EventBus into infra layer, unify event pipeline, add integration test harness #402

Description

@ElioNeto

Problem

Several architecture issues were identified during the v2.2.0 implementation:

1. EventBus lives in api layer, should be in infra

src/api/events.rs contains the EventBus CDC publisher — a general-purpose pub/sub mechanism. It imports from crate::infra::cdc but is itself in the api layer. This violates layering: the infra layer should own the event bus abstraction, and api should only wire it up.

Impact: Any non-API code that wants to subscribe to engine events (e.g., TUI, CLI, Notes) would need to depend on the API module.

2. CDC publisher chain is ad-hoc

The MultiPublisher in src/infra/cdc.rs solves the immediate need to fan out to EventBus + webhook, but it has no backpressure, no error isolation, and no monitoring. A single slow publisher blocks the entire chain synchronously.

3. TransactionManager uses std::sync::Mutex under actix-web

The TransactionManager in src/api/mod.rs protects active transactions with std::sync::Mutex<HashMap<u64, Transaction>>. The take/insert pattern for every txn_put/txn_delete is:

  • High contention under load (serializes all transaction mutations)
  • Race-prone (forgotten re-inserts leave dangling transactions)
  • Not integrated with actix-webs timeout/cleanup — transactions can leak

4. API module is 1900+ lines

src/api/mod.rs has grown to ~1920 lines containing:

  • Route registrations
  • Handler functions
  • Request/response types (Deserialize structs)
  • Server startup logic (TLS, CDC, middleware)
  • Transaction management
    This violates single-responsibility and makes testing hard.

5. No HTTP integration test infrastructure

Unlike the engine (which has extensive unit tests via #[cfg(test)]), there is zero test infrastructure for HTTP-level tests. No shared test helpers, no test server builder, no fixture system.

Proposed Solution

Phase 1: Move EventBus to infra

  • Move EventBus from src/api/events.rs to src/infra/events.rs
  • Implement CdcPublisher for EventBus there
  • Add subscribe() method returning tokio::sync::broadcast::Receiver<CdcEvent>
  • Re-export from src/infra/mod.rs
  • Update API module to import from crate::infra::events

Phase 2: Create API test harness

  • Create src/api/test_helpers.rs with:
    • fn test_server(engine: LsmEngine) -> impl Service — builds an actix-web test app
    • fn test_engine() -> (LsmEngine, TempDir) — creates engine with test config
    • Common fixture setup functions
  • This enables writing integration tests as unit tests in api module or integration tests in tests/

Phase 3: Split api/mod.rs into modules

  • src/api/routes.rs — all route registrations and handler functions
  • src/api/types.rs — all request/response Deserialize structs
  • src/api/server.rs — server startup, TLS, middleware wiring
  • src/api/transactions.rs — TransactionManager and txn handlers
  • src/api/mod.rs — re-exports and module declarations

Phase 4: Improve TransactionManager

  • Use tokio::sync::RwLock<HashMap<u64, Transaction>> instead of std::sync::Mutex
  • Add TTL-based cleanup for abandoned transactions
  • Simplify API to avoid take/insert pattern

Acceptance criteria

  • No functional changes — all existing tests pass
  • EventBus can be imported from crate::infra::events
  • Test harness can be used by new integration tests
  • api/mod.rs is < 500 lines after splitting
  • Transaction cleanup prevents leaks

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