|
26 | 26 | import java.io.IOException; |
27 | 27 | import java.util.*; |
28 | 28 | import java.util.concurrent.Callable; |
| 29 | +import java.util.concurrent.ExecutionException; |
29 | 30 | import java.util.concurrent.ExecutorService; |
30 | 31 | import java.util.concurrent.Executors; |
| 32 | +import java.util.concurrent.Future; |
| 33 | +import java.util.concurrent.atomic.AtomicInteger; |
31 | 34 | import java.util.stream.Collectors; |
32 | 35 |
|
33 | 36 | public class RuleExecutor { |
@@ -114,7 +117,7 @@ public List<InvalidContent> execute( |
114 | 117 | checkComponentsIntegrity(concepts, conceptService); |
115 | 118 |
|
116 | 119 | final List<List<InvalidContent>> sessionInvalidContent = new ArrayList<>(); |
117 | | - final List<InvalidContent> exceptionContents = new ArrayList<>(); |
| 120 | + final List<InvalidContent> exceptionContents = Collections.synchronizedList(new ArrayList<>()); |
118 | 121 | int threads = concepts.size() == 1 ? 1 : 10; |
119 | 122 |
|
120 | 123 | Map<String, List<StatelessKieSession>> sessionMap = createKieSessionMap(ruleSetNames, conceptService, descriptionService, relationshipService, threads, sessionInvalidContent); |
@@ -149,38 +152,38 @@ private void doValidateComponents(Collection<? extends Concept> concepts, boolea |
149 | 152 | Date start = new Date(); |
150 | 153 | try (ExecutorService executorService = Executors.newFixedThreadPool(threads)) { |
151 | 154 | List<Concept> conceptList = new ArrayList<>(concepts); |
152 | | - List<Callable<String>> tasks = new ArrayList<>(); |
| 155 | + List<Callable<String>> workers = new ArrayList<>(threads); |
| 156 | + AtomicInteger nextConceptIndex = new AtomicInteger(); |
| 157 | + AtomicInteger completedConceptCount = new AtomicInteger(); |
153 | 158 | String total = String.format("%,d", concepts.size()); |
154 | | - int i = 0; |
155 | | - while (i < concepts.size()) { |
156 | | - Set<Component> components = new HashSet<>(); |
157 | | - Concept concept = conceptList.get(i++); |
158 | | - addConcept(components, concept, includeInferredRelationships); |
159 | | - int sessionIndex = tasks.size(); |
160 | | - tasks.add(() -> { |
161 | | - try { |
162 | | - List<StatelessKieSession> statelessKieSessions = sessionMap.get(String.valueOf(sessionIndex)); |
163 | | - statelessKieSessions.forEach(statelessKieSession -> statelessKieSession.execute(components)); |
164 | | - components.clear(); |
165 | | - } catch (Exception e) { |
166 | | - exceptionContents.add(new InvalidContent(concept.getId(), concept, "An error occurred while running concept validation. Technical detail: " + e.getMessage(), Severity.ERROR)); |
| 159 | + |
| 160 | + for (int workerIndex = 0; workerIndex < threads; workerIndex++) { |
| 161 | + List<StatelessKieSession> statelessKieSessions = sessionMap.get(String.valueOf(workerIndex)); |
| 162 | + workers.add(() -> { |
| 163 | + int conceptIndex; |
| 164 | + while ((conceptIndex = nextConceptIndex.getAndIncrement()) < conceptList.size()) { |
| 165 | + Concept concept = conceptList.get(conceptIndex); |
| 166 | + Set<Component> components = new HashSet<>(); |
| 167 | + addConcept(components, concept, includeInferredRelationships); |
| 168 | + try { |
| 169 | + statelessKieSessions.forEach(statelessKieSession -> statelessKieSession.execute(components)); |
| 170 | + } catch (Exception e) { |
| 171 | + exceptionContents.add(new InvalidContent(concept.getId(), concept, "An error occurred while running concept validation. Technical detail: " + e.getMessage(), Severity.ERROR)); |
| 172 | + } finally { |
| 173 | + components.clear(); |
| 174 | + } |
| 175 | + |
| 176 | + int completed = completedConceptCount.incrementAndGet(); |
| 177 | + if (completed % 10_000 == 0) { |
| 178 | + logger.info("Validated {} of {}", String.format("%,d", completed), total); |
| 179 | + } |
167 | 180 | } |
168 | 181 | return null; |
169 | 182 | }); |
170 | | - |
171 | | - if (tasks.size() == threads) { |
172 | | - runTasks(executorService, tasks); |
173 | | - tasks.clear(); |
174 | | - } |
175 | | - if (i % 10_000 == 0) { |
176 | | - logger.info("Validated {} of {}", String.format("%,d", i), total); |
177 | | - } |
178 | | - } |
179 | | - if (!tasks.isEmpty()) { |
180 | | - runTasks(executorService, tasks); |
181 | 183 | } |
| 184 | + runTasks(executorService, workers); |
182 | 185 |
|
183 | | - logger.info("Validated {} of {}", String.format("%,d", i), total); |
| 186 | + logger.info("Validated {} of {}", String.format("%,d", completedConceptCount.get()), total); |
184 | 187 | logger.info("Rule execution took {} seconds", (new Date().getTime() - start.getTime()) / 1000); |
185 | 188 | } |
186 | 189 | } |
@@ -317,9 +320,14 @@ private StatelessKieSession newStatelessKieSession(KieContainer kieContainer, Co |
317 | 320 |
|
318 | 321 | private void runTasks(ExecutorService executorService, List<Callable<String>> tasks) { |
319 | 322 | try { |
320 | | - executorService.invokeAll(tasks); |
| 323 | + for (Future<String> task : executorService.invokeAll(tasks)) { |
| 324 | + task.get(); |
| 325 | + } |
321 | 326 | } catch (InterruptedException e) { |
| 327 | + Thread.currentThread().interrupt(); |
322 | 328 | throw new RuleExecutorException("Validation tasks were interrupted.", e); |
| 329 | + } catch (ExecutionException e) { |
| 330 | + throw new RuleExecutorException("A validation worker failed.", e.getCause()); |
323 | 331 | } |
324 | 332 | } |
325 | 333 |
|
|
0 commit comments