GapDetector integration in PdoEventStoreReadModelProjector remains a critical enhancement for ES/CQRS architectures, ensuring projection reliability by detecting and handling missing events during replay. This is particularly valuable for eventual consistency in distributed systems, where partial event histories are a risk.GapDetector enables self-healing projections, reducing the need for manual intervention during event replay.GapDetector is now natively integrated into PdoEventStoreReadModelProjector, reducing projection failures when used with Prooph’s Service Bus or Snapshotter. Teams already using Prooph’s projection tools will see minimal adaptation overhead.event_id, stream_name) required for gap detection.GapDetector operates at the projection layer, not the event store schema.event_version) is unaffected.GapDetector: Projections are now more resilient to partial event history, easing migration from non-event-driven systems.GapDetector overhead degrade replay speed for high-volume streams? Test with load simulations and real-world event distributions.Log::error, custom metrics, or observability tools like Datadog).stream_name, event_id, and event_version are indexed for optimal gap detection performance.GapDetector enhances read model projections, which can be implemented as:
prooph/service-bus).HandleGapException).ReadModelProjector) to leverage GapDetector. Alternatives like EventSauce lack Laravel integration.WHERE event_id NOT IN (...) queries).WHERE event_id > last_processed_id).GapDetector with a sample projection to validate gap handling.$eventStore->deleteEventsFromStream('stream-1', ['event-id-2']);
$projector->project($streamName, $handler);
$this->assertEquals(['event-1', 'event-3'], $readModel->getEvents());
PdoEventStoreReadModelProjector + GapDetector.event_id and stream_name for faster gap queries.GapDetector to skip known gaps during initial sync.ReadModelProjector with GapDetector:
$app->bind(ReadModelProjector::class, function ($app) {
return new PdoEventStoreReadModelProjector(
$app->make(EventStore::class),
new GapDetector(), // Native integration in v1.16.5
$app->make(EventSerializer::class)
);
});
event_id, stream_name).GapDetector operates outside transactions by design. Use Laravel’s queue retries for idempotent gap handling.// Example: Simulate a gap and assert projection recovery
$eventStore->deleteEventsFromStream('stream-1', ['event-id-2']);
$projector->project($streamName, $handler);
$this->assertEquals(['event-1', 'event-3'], $readModel->getEvents());
CREATE INDEX idx_event_store_stream_event_id ON event_store(stream_name, event_id);
ReadModelProjector with GapDetector:
$projector = new PdoEventStoreReadModelProjector(
$eventStore,
new GapDetector(), // Native in v1.16.5
$serializer
);
ReadModelProjectorHandler with gap-aware logic:
$projector->project('order-stream', new OrderProjectionHandler());
GapDetector to log gaps to Laravel’s monitoring tools:
$gapDetector->onGapDetected(function (Gap $gap) {
Log::warning("Gap detected in stream {$gap->getStreamName()}: missing event {$gap->getExpectedEventId()}");
});
prooph/service-bus:^2.0).$gapDetector->onGapDetected(function (Gap $gap) {
Log::warning("Gap detected in stream {$gap->getStreamName()}: missing event {$gap->getExpectedEventId()}");
});
How can I help you explore Laravel packages today?