search: SearchRequest.afterExecutionId — composite (startTime, execId) predicate
Adds an optional afterExecutionId field to SearchRequest. When combined with a non-null timeFrom, ClickHouseSearchIndex applies a strictly-after tuple predicate (start_time > ts OR (start_time = ts AND execution_id > id)) so same-millisecond exchanges can be consumed exactly once across ticks. When afterExecutionId is null, timeFrom keeps its existing >= semantics — no behaviour change for any current caller. Also adds the SearchRequest.withCursor(ts, id) wither. Threads the field through existing withInstanceIds / withEnvironment witheres. All existing positional call-sites (SearchController, ExchangeMatchEvaluator, ClickHouseSearchIndexIT, ClickHouseChunkPipelineIT) pass null for the new slot. Task 1.2 of docs/superpowers/plans/2026-04-22-per-exchange-exactly-once.md. The evaluator-side wiring that actually supplies the cursor is Task 1.5.
This commit is contained in:
@@ -110,6 +110,7 @@ public class ExchangeMatchEvaluator implements ConditionEvaluator<ExchangeMatchC
|
||||
50,
|
||||
"startTime",
|
||||
"asc", // asc so we process oldest first
|
||||
null, // afterExecutionId (wired in Task 1.5)
|
||||
envSlug
|
||||
);
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ public class SearchController {
|
||||
application, null,
|
||||
offset, limit,
|
||||
sortField, sortDir,
|
||||
null,
|
||||
env.slug()
|
||||
);
|
||||
|
||||
|
||||
@@ -124,7 +124,13 @@ public class ClickHouseSearchIndex implements SearchIndex {
|
||||
conditions.add("tenant_id = ?");
|
||||
params.add(tenantId);
|
||||
|
||||
if (request.timeFrom() != null) {
|
||||
if (request.timeFrom() != null && request.afterExecutionId() != null) {
|
||||
// composite predicate: strictly-after in (start_time, execution_id) tuple order
|
||||
conditions.add("(start_time > ? OR (start_time = ? AND execution_id > ?))");
|
||||
params.add(Timestamp.from(request.timeFrom()));
|
||||
params.add(Timestamp.from(request.timeFrom()));
|
||||
params.add(request.afterExecutionId());
|
||||
} else if (request.timeFrom() != null) {
|
||||
conditions.add("start_time >= ?");
|
||||
params.add(Timestamp.from(request.timeFrom()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user