|
17 | 17 |
|
18 | 18 | import io.serverlessworkflow.impl.TaskContextData; |
19 | 19 | import io.serverlessworkflow.impl.WorkflowContextData; |
| 20 | +import io.serverlessworkflow.impl.WorkflowDefinitionData; |
20 | 21 | import io.serverlessworkflow.impl.WorkflowStatus; |
| 22 | +import java.time.Duration; |
| 23 | +import java.util.Map; |
| 24 | +import java.util.Optional; |
| 25 | +import java.util.concurrent.CompletableFuture; |
| 26 | +import java.util.concurrent.ConcurrentHashMap; |
| 27 | +import java.util.concurrent.ExecutorService; |
| 28 | +import java.util.concurrent.TimeUnit; |
21 | 29 | import java.util.function.Consumer; |
22 | 30 |
|
23 | 31 | public class DefaultPersistenceInstanceWriter implements PersistenceInstanceWriter { |
24 | 32 |
|
25 | 33 | private final PersistenceInstanceStore store; |
| 34 | + private final Map<String, CompletableFuture<Void>> futuresMap = new ConcurrentHashMap<>(); |
| 35 | + private final Optional<ExecutorService> executorService; |
| 36 | + private final Duration closeTimeout; |
26 | 37 |
|
27 | | - protected DefaultPersistenceInstanceWriter(PersistenceInstanceStore store) { |
| 38 | + protected DefaultPersistenceInstanceWriter( |
| 39 | + PersistenceInstanceStore store, |
| 40 | + Optional<ExecutorService> executorService, |
| 41 | + Duration closeTimeout) { |
28 | 42 | this.store = store; |
| 43 | + this.executorService = executorService; |
| 44 | + this.closeTimeout = closeTimeout; |
29 | 45 | } |
30 | 46 |
|
31 | 47 | @Override |
32 | | - public void started(WorkflowContextData workflowContext) { |
33 | | - doTransaction(t -> t.writeInstanceData(workflowContext), workflowContext); |
| 48 | + public CompletableFuture<Void> started(WorkflowContextData workflowContext) { |
| 49 | + return doTransaction(t -> t.writeInstanceData(workflowContext), workflowContext); |
34 | 50 | } |
35 | 51 |
|
36 | 52 | @Override |
37 | | - public void completed(WorkflowContextData workflowContext) { |
38 | | - removeProcessInstance(workflowContext); |
| 53 | + public CompletableFuture<Void> completed(WorkflowContextData workflowContext) { |
| 54 | + return removeProcessInstance(workflowContext); |
39 | 55 | } |
40 | 56 |
|
41 | 57 | @Override |
42 | | - public void failed(WorkflowContextData workflowContext, Throwable ex) { |
43 | | - removeProcessInstance(workflowContext); |
| 58 | + public CompletableFuture<Void> failed(WorkflowContextData workflowContext, Throwable ex) { |
| 59 | + return removeProcessInstance(workflowContext); |
44 | 60 | } |
45 | 61 |
|
46 | 62 | @Override |
47 | | - public void aborted(WorkflowContextData workflowContext) { |
48 | | - removeProcessInstance(workflowContext); |
| 63 | + public CompletableFuture<Void> aborted(WorkflowContextData workflowContext) { |
| 64 | + return removeProcessInstance(workflowContext); |
49 | 65 | } |
50 | 66 |
|
51 | | - protected void removeProcessInstance(WorkflowContextData workflowContext) { |
52 | | - doTransaction(t -> t.removeProcessInstance(workflowContext), workflowContext); |
| 67 | + protected CompletableFuture<Void> removeProcessInstance(WorkflowContextData workflowContext) { |
| 68 | + return doTransaction(t -> t.removeProcessInstance(workflowContext), workflowContext) |
| 69 | + .thenRun(() -> futuresMap.remove(workflowContext.instanceData().id())); |
53 | 70 | } |
54 | 71 |
|
55 | 72 | @Override |
56 | | - public void taskStarted(WorkflowContextData workflowContext, TaskContextData taskContext) { |
57 | | - // not recording |
| 73 | + public CompletableFuture<Void> taskStarted( |
| 74 | + WorkflowContextData workflowContext, TaskContextData taskContext) { |
| 75 | + return CompletableFuture.completedFuture(null); |
58 | 76 | } |
59 | 77 |
|
60 | 78 | @Override |
61 | | - public void taskRetried(WorkflowContextData workflowContext, TaskContextData taskContext) { |
62 | | - doTransaction(t -> t.writeRetryTask(workflowContext, taskContext), workflowContext); |
| 79 | + public CompletableFuture<Void> taskRetried( |
| 80 | + WorkflowContextData workflowContext, TaskContextData taskContext) { |
| 81 | + return doTransaction(t -> t.writeRetryTask(workflowContext, taskContext), workflowContext); |
63 | 82 | } |
64 | 83 |
|
65 | 84 | @Override |
66 | | - public void taskCompleted(WorkflowContextData workflowContext, TaskContextData taskContext) { |
67 | | - doTransaction(t -> t.writeCompletedTask(workflowContext, taskContext), workflowContext); |
| 85 | + public CompletableFuture<Void> taskCompleted( |
| 86 | + WorkflowContextData workflowContext, TaskContextData taskContext) { |
| 87 | + return doTransaction(t -> t.writeCompletedTask(workflowContext, taskContext), workflowContext); |
68 | 88 | } |
69 | 89 |
|
70 | 90 | @Override |
71 | | - public void suspended(WorkflowContextData workflowContext) { |
72 | | - doTransaction(t -> t.writeStatus(workflowContext, WorkflowStatus.SUSPENDED), workflowContext); |
| 91 | + public CompletableFuture<Void> suspended(WorkflowContextData workflowContext) { |
| 92 | + return doTransaction( |
| 93 | + t -> t.writeStatus(workflowContext, WorkflowStatus.SUSPENDED), workflowContext); |
73 | 94 | } |
74 | 95 |
|
75 | 96 | @Override |
76 | | - public void resumed(WorkflowContextData workflowContext) { |
77 | | - doTransaction(t -> t.clearStatus(workflowContext), workflowContext); |
| 97 | + public CompletableFuture<Void> resumed(WorkflowContextData workflowContext) { |
| 98 | + return doTransaction(t -> t.clearStatus(workflowContext), workflowContext); |
78 | 99 | } |
79 | 100 |
|
80 | | - private void doTransaction( |
81 | | - Consumer<PersistenceInstanceTransaction> operations, WorkflowContextData context) { |
| 101 | + private CompletableFuture<Void> doTransaction( |
| 102 | + Consumer<PersistenceInstanceTransaction> operation, WorkflowContextData context) { |
| 103 | + final ExecutorService service = |
| 104 | + this.executorService.orElse(context.definition().application().executorService()); |
| 105 | + final Runnable runnable = () -> executeTransaction(operation, context.definition()); |
| 106 | + return futuresMap.compute( |
| 107 | + context.instanceData().id(), |
| 108 | + (k, v) -> |
| 109 | + v == null |
| 110 | + ? CompletableFuture.runAsync(runnable, service) |
| 111 | + : v.thenRunAsync(runnable, service)); |
| 112 | + } |
| 113 | + |
| 114 | + private void executeTransaction( |
| 115 | + Consumer<PersistenceInstanceTransaction> operation, WorkflowDefinitionData definition) { |
82 | 116 | PersistenceInstanceTransaction transaction = store.begin(); |
83 | 117 | try { |
84 | | - operations.accept(transaction); |
85 | | - transaction.commit(context.definition()); |
| 118 | + operation.accept(transaction); |
| 119 | + transaction.commit(definition); |
86 | 120 | } catch (Exception ex) { |
87 | | - transaction.rollback(context.definition()); |
| 121 | + transaction.rollback(definition); |
88 | 122 | throw ex; |
89 | 123 | } |
90 | 124 | } |
| 125 | + |
| 126 | + @Override |
| 127 | + public void close() { |
| 128 | + futuresMap.clear(); |
| 129 | + executorService.ifPresent( |
| 130 | + e -> { |
| 131 | + try { |
| 132 | + e.awaitTermination(closeTimeout.toMillis(), TimeUnit.MILLISECONDS); |
| 133 | + e.shutdown(); |
| 134 | + } catch (InterruptedException ex) { |
| 135 | + Thread.currentThread().interrupt(); |
| 136 | + } |
| 137 | + }); |
| 138 | + } |
91 | 139 | } |
0 commit comments