Implement run_projection free function (ADR-029) #258

Closed
opened 2025-12-29 18:16:10 -08:00 by jwilger · 0 comments
jwilger commented 2025-12-29 18:16:10 -08:00 (Migrated from github.com)

Overview

Replace ProjectionRunner struct with run_projection(projector, &backend) free function per ADR-029 and ARCHITECTURE.md v2.7.

Parent Epic: #237

Context

Issue #239 implemented the ProjectorCoordinator trait and backends:

  • InMemoryProjectorCoordinator for single-process deployments
  • PostgresProjectorCoordinator using pg_try_advisory_lock

ADR-029 (accepted 2025-12-30) simplified the API:

  • Free function instead of builder pattern
  • Single backend parameter implementing all required traits
  • Matches execute(command, &store) ergonomics

Required Changes

Per ADR-029 and ARCHITECTURE.md v2.7:

/// Runs a projector against a backend that provides events, checkpoints, and coordination.
pub async fn run_projection<P, B>(
    projector: P,
    backend: &B,
) -> Result<(), ProjectionError>
where
    P: Projector,
    B: EventReader + CheckpointStore + ProjectorCoordinator,

Implementation

  1. Create run_projection free function in eventcore/src/projection.rs
  2. Require backend to implement EventReader + CheckpointStore + ProjectorCoordinator
  3. Call try_acquire() at start, hold guard for duration
  4. Return ProjectionError::CoordinationError if leadership unavailable
  5. Remove or deprecate ProjectionRunner struct

API Change

Before:

ProjectionRunner::new(projector, &event_reader)
    .with_checkpoint_store(&checkpoint_store)
    .run()

After:

// Simple case (99.9%) - backend implements all three traits
run_projection(my_projector, &postgres_store).await?;

// Mixed backend case - wrapper struct
run_projection(my_projector, &my_backend).await?;

Acceptance Criteria

  • run_projection(projector, &backend) free function created
  • Backend must implement EventReader + CheckpointStore + ProjectorCoordinator
  • run_projection acquires leadership before processing events
  • Returns ProjectionError if leadership unavailable (non-blocking per ADR-028)
  • Guard held for duration of event processing
  • Integration test verifies coordination behavior
  • ProjectionRunner struct removed or deprecated
  • InMemoryEventStore implements all three traits
  • PostgresEventStore implements all three traits

References

  • Parent: #237
  • Predecessor: #239 (coordinator infrastructure)
  • ADR-028: Advisory Lock Acquisition Behavior
  • ADR-029: Projection Runner API Simplification
  • ARCHITECTURE.md v2.7: Projection Runner API section
## Overview Replace `ProjectionRunner` struct with `run_projection(projector, &backend)` free function per ADR-029 and ARCHITECTURE.md v2.7. **Parent Epic**: #237 ## Context Issue #239 implemented the `ProjectorCoordinator` trait and backends: - `InMemoryProjectorCoordinator` for single-process deployments - `PostgresProjectorCoordinator` using `pg_try_advisory_lock` ADR-029 (accepted 2025-12-30) simplified the API: - Free function instead of builder pattern - Single backend parameter implementing all required traits - Matches `execute(command, &store)` ergonomics ## Required Changes Per ADR-029 and ARCHITECTURE.md v2.7: ```rust /// Runs a projector against a backend that provides events, checkpoints, and coordination. pub async fn run_projection<P, B>( projector: P, backend: &B, ) -> Result<(), ProjectionError> where P: Projector, B: EventReader + CheckpointStore + ProjectorCoordinator, ``` ### Implementation 1. Create `run_projection` free function in `eventcore/src/projection.rs` 2. Require backend to implement `EventReader + CheckpointStore + ProjectorCoordinator` 3. Call `try_acquire()` at start, hold guard for duration 4. Return `ProjectionError::CoordinationError` if leadership unavailable 5. Remove or deprecate `ProjectionRunner` struct ### API Change Before: ```rust ProjectionRunner::new(projector, &event_reader) .with_checkpoint_store(&checkpoint_store) .run() ``` After: ```rust // Simple case (99.9%) - backend implements all three traits run_projection(my_projector, &postgres_store).await?; // Mixed backend case - wrapper struct run_projection(my_projector, &my_backend).await?; ``` ## Acceptance Criteria - [ ] `run_projection(projector, &backend)` free function created - [ ] Backend must implement `EventReader + CheckpointStore + ProjectorCoordinator` - [ ] `run_projection` acquires leadership before processing events - [ ] Returns `ProjectionError` if leadership unavailable (non-blocking per ADR-028) - [ ] Guard held for duration of event processing - [ ] Integration test verifies coordination behavior - [ ] `ProjectionRunner` struct removed or deprecated - [ ] `InMemoryEventStore` implements all three traits - [ ] `PostgresEventStore` implements all three traits ## References - Parent: #237 - Predecessor: #239 (coordinator infrastructure) - ADR-028: Advisory Lock Acquisition Behavior - ADR-029: Projection Runner API Simplification - ARCHITECTURE.md v2.7: Projection Runner API section
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
jwilger/eventcore#258
No description provided.