fix(notifications): dispatcher race с OutboxPoller — emails never sent
This commit is contained in:
+27
@@ -5,6 +5,8 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface OutboxEventRepository extends JpaRepository<OutboxEvent, Long> {
|
||||
@@ -20,6 +22,31 @@ public interface OutboxEventRepository extends JpaRepository<OutboxEvent, Long>
|
||||
""")
|
||||
List<OutboxEvent> findUnpublished(Pageable pageable);
|
||||
|
||||
/**
|
||||
* Recent events filtered by event_type, regardless of {@code published_at}.
|
||||
* Used by NotificationsDispatcher (and future side-channel processors) что
|
||||
* RACE с OutboxPoller (Kafka publisher) — Poller polls every 1s и flips
|
||||
* {@code published_at} быстрее чем 30s notifications tick → notifications
|
||||
* никогда не находил event'ы с {@link #findUnpublished}.
|
||||
*
|
||||
* <p>Idempotency обеспечивается через own dedupe table (notification_log
|
||||
* UNIQUE (event_id, channel, recipient)) — same event может быть processed
|
||||
* многократно без duplicate sends.
|
||||
*
|
||||
* @param types event_type filter (e.g. RecordDraftSubmitted, ...)
|
||||
* @param since createdAt cutoff — обычно last 24h чтобы не сканировать
|
||||
* историческую таблицу при cold start
|
||||
*/
|
||||
@Query("""
|
||||
SELECT o FROM OutboxEvent o
|
||||
WHERE o.eventType IN :types
|
||||
AND o.createdAt >= :since
|
||||
AND o.dlqAt IS NULL
|
||||
ORDER BY o.id ASC
|
||||
""")
|
||||
List<OutboxEvent> findRecentByEventTypes(
|
||||
Collection<String> types, OffsetDateTime since, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Сколько ожидает публикации (без DLQ). Метрика
|
||||
* {@code ordinis_outbox_pending_events}.
|
||||
|
||||
Reference in New Issue
Block a user