feat: persist process history events, listeners, and ACTION executions
Give hosts an append-only timeline, post-commit OrdoEventListener hooks, and durable ACTION results without blocking the approval flow. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+24
-2
@@ -3,17 +3,23 @@ package com.jetlumen.ordo.spring;
|
||||
import com.jetlumen.ordo.api.ActionHandler;
|
||||
import com.jetlumen.ordo.api.AssigneeResolver;
|
||||
import com.jetlumen.ordo.api.OrdoEngine;
|
||||
import com.jetlumen.ordo.api.OrdoEventListener;
|
||||
import com.jetlumen.ordo.api.RoutingCondition;
|
||||
import com.jetlumen.ordo.api.TransactionExecutor;
|
||||
import com.jetlumen.ordo.api.repository.ActionExecutionRepository;
|
||||
import com.jetlumen.ordo.api.repository.ApprovalTaskRepository;
|
||||
import com.jetlumen.ordo.api.repository.ProcessDefinitionRepository;
|
||||
import com.jetlumen.ordo.api.repository.ProcessHistoryRepository;
|
||||
import com.jetlumen.ordo.api.repository.ProcessInstanceRepository;
|
||||
import com.jetlumen.ordo.core.DefaultOrdoEngine;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcActionExecutionRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcApprovalTaskRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcConnectionProvider;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcProcessDefinitionRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcProcessHistoryRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcProcessInstanceRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcTransactionExecutor;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -103,6 +109,18 @@ public class OrdoJdbcAutoConfiguration {
|
||||
return new JdbcApprovalTaskRepository(connectionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ProcessHistoryRepository ordoProcessHistoryRepository(JdbcConnectionProvider connectionProvider) {
|
||||
return new JdbcProcessHistoryRepository(connectionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ActionExecutionRepository ordoActionExecutionRepository(JdbcConnectionProvider connectionProvider) {
|
||||
return new JdbcActionExecutionRepository(connectionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OrdoEngine ordoEngine(Clock ordoClock,
|
||||
@@ -112,10 +130,14 @@ public class OrdoJdbcAutoConfiguration {
|
||||
TransactionExecutor ordoTransactionExecutor,
|
||||
ProcessDefinitionRepository ordoProcessDefinitionRepository,
|
||||
ProcessInstanceRepository ordoProcessInstanceRepository,
|
||||
ApprovalTaskRepository ordoApprovalTaskRepository) {
|
||||
ApprovalTaskRepository ordoApprovalTaskRepository,
|
||||
ProcessHistoryRepository ordoProcessHistoryRepository,
|
||||
ActionExecutionRepository ordoActionExecutionRepository,
|
||||
ObjectProvider<OrdoEventListener> ordoEventListeners) {
|
||||
return new DefaultOrdoEngine(ordoClock, ordoAssigneeResolver, ordoRoutingCondition, actionHandler,
|
||||
ordoTransactionExecutor, ordoProcessDefinitionRepository, ordoProcessInstanceRepository,
|
||||
ordoApprovalTaskRepository);
|
||||
ordoApprovalTaskRepository, ordoProcessHistoryRepository, ordoActionExecutionRepository,
|
||||
ordoEventListeners.orderedStream().toList());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+42
@@ -5,9 +5,13 @@ import com.jetlumen.ordo.api.ApprovalStep;
|
||||
import com.jetlumen.ordo.api.ApprovalTask;
|
||||
import com.jetlumen.ordo.api.AssigneeResolver;
|
||||
import com.jetlumen.ordo.api.OrdoEngine;
|
||||
import com.jetlumen.ordo.api.OrdoEventListener;
|
||||
import com.jetlumen.ordo.api.ProcessDefinition;
|
||||
import com.jetlumen.ordo.api.ProcessEvent;
|
||||
import com.jetlumen.ordo.api.ProcessEventType;
|
||||
import com.jetlumen.ordo.api.ProcessInstance;
|
||||
import com.jetlumen.ordo.api.RoutingCondition;
|
||||
import com.jetlumen.ordo.api.query.PageRequest;
|
||||
import com.jetlumen.ordo.api.repository.ProcessDefinitionRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
@@ -151,6 +155,27 @@ class OrdoJdbcAutoConfigurationTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void invokesOrdoEventListenerBeans() {
|
||||
withDataSourceRunner.withUserConfiguration(RecordingListenerConfig.class)
|
||||
.run(context -> {
|
||||
OrdoEngine engine = context.getBean(OrdoEngine.class);
|
||||
engine.register(LEAVE_REQUEST);
|
||||
ProcessInstance instance = engine.start("leave-request", "alice");
|
||||
engine.approve(engine.findPendingTasksByAssignee("maria").getFirst().id(), "maria");
|
||||
|
||||
RecordingListener listener = context.getBean(RecordingListener.class);
|
||||
assertThat(listener.types).contains(
|
||||
ProcessEventType.INSTANCE_STARTED,
|
||||
ProcessEventType.TASK_CREATED,
|
||||
ProcessEventType.TASK_APPROVED,
|
||||
ProcessEventType.INSTANCE_APPROVED);
|
||||
assertThat(listener.types.getFirst()).isEqualTo(ProcessEventType.INSTANCE_STARTED);
|
||||
assertThat(engine.queryHistory(instance.id(), new PageRequest(0, 20))
|
||||
.totalElements()).isGreaterThan(0);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomAssigneeResolverConfig {
|
||||
@Bean
|
||||
@@ -176,4 +201,21 @@ class OrdoJdbcAutoConfigurationTest {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static class RecordingListener implements OrdoEventListener {
|
||||
final List<ProcessEventType> types = new java.util.concurrent.CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onEvent(ProcessEvent event) {
|
||||
types.add(event.type());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RecordingListenerConfig {
|
||||
@Bean
|
||||
RecordingListener recordingListener() {
|
||||
return new RecordingListener();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user