feat: schedule due processing from next dueAt instead of polling

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
0264408
2026-09-20 16:54:13 +08:00
co-authored by Cursor
parent 8d08a2840b
commit 02557a9b86
15 changed files with 183 additions and 12 deletions
@@ -345,6 +345,11 @@ public final class DefaultOrdoEngine implements OrdoEngine {
return processed;
}
@Override
public synchronized Optional<Instant> nextDueAt() {
return taskRepository.findNextDueAt();
}
private boolean escalateDueTask(ApprovalTask overdue, Instant now, List<PendingAction> queued,
List<ProcessEvent> events) {
if (!taskRepository.claimIfDue(overdue.id(), overdue.assignee(), now)) {
@@ -23,6 +23,7 @@ import com.jetlumen.ordo.core.repository.InMemoryProcessHistoryRepository;
import com.jetlumen.ordo.core.repository.InMemoryProcessInstanceRepository;
import java.time.Clock;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
@@ -181,4 +182,9 @@ public final class InMemoryOrdoEngine implements OrdoEngine {
public int processDue(int limit) {
return delegate.processDue(limit);
}
@Override
public Optional<Instant> nextDueAt() {
return delegate.nextDueAt();
}
}
@@ -113,6 +113,15 @@ public final class InMemoryApprovalTaskRepository implements ApprovalTaskReposit
.toList();
}
@Override
public synchronized Optional<Instant> findNextDueAt() {
return tasks.values().stream()
.filter(task -> task.status() == TaskStatus.PENDING)
.map(ApprovalTask::dueAt)
.filter(Objects::nonNull)
.min(Comparator.naturalOrder());
}
@Override
public synchronized boolean claimIfDue(String taskId, String expectedAssignee, Instant now) {
ApprovalTask current = tasks.get(taskId);