To avoid losing events due to PostgreSQL sequence non-rollback behavior, the system uses a combination of TRANSACTION_ID and EVENT_ID for polling.
By using pg_current_xact_id() and checking against pg_snapshot_xmin(pg_current_snapshot()), the subscriber ensures it only processes events from transactions that are guaranteed to be committed. This prevents the 'naive' outbox problem where a later transaction commits before an earlier one, causing the subscriber to skip the earlier event.
-- 1. Acquire lock on subscription and get last processed markers
SELECT LAST_TRANSACTION_ID::text,
LAST_EVENT_ID
FROM ES_EVENT_SUBSCRIPTION
WHERE SUBSCRIPTION_NAME = :subscriptionName
FOR UPDATE SKIP LOCKED;
-- 2. Read new 'safe' events (committed and visible)
SELECT e.ID,
e.TRANSACTION_ID::text,
e.EVENT_TYPE,
e.JSON_DATA
FROM ES_EVENT e
JOIN ES_AGGREGATE a on a.ID = e.AGGREGATE_ID
WHERE a.AGGREGATE_TYPE = :aggregateType
AND (e.TRANSACTION_ID, e.ID) > (:lastProcessedTransactionId::xid8, :lastProcessedEventId)
AND e.TRANSACTION_ID < pg_snapshot_xmin(pg_current_snapshot())
ORDER BY e.TRANSACTION_ID ASC, e.ID ASC;
-- 3. Update subscription progress
UPDATE ES_EVENT_SUBSCRIPTION
SET LAST_TRANSACTION_ID = :lastProcessedTransactionId::xid8,
LAST_EVENT_ID = :lastProcessedEventId
WHERE SUBSCRIPTION_NAME = :subscriptionName;