@@ -136,6 +136,13 @@ public final class BatchContext<PropertiesT> implements Closeable {
136136 private final CollectionDescriptor <PropertiesT > collectionDescriptor ;
137137 private final CollectionHandleDefaults collectionHandleDefaults ;
138138
139+ /**
140+ * Tally of the failed items. This value is only written to from
141+ * {@link #retryService} thread, which processes the incoming
142+ * {@link Event.Results}; making it {@code volatile} is sufficient.
143+ */
144+ private volatile int numberOfErrors ;
145+
139146 /**
140147 * Internal execution service. Its lifecycle is bound to that of the
141148 * BatchContext: it's started when the context is initialized
@@ -314,12 +321,25 @@ private TaskHandle add(final TaskHandle taskHandle) throws InterruptedException
314321 // Remove the task from the WIP list as soon as it completes,
315322 // successfully or otherwise. Note, that TaskHandle::done future
316323 // only completes exceptionally after all retries have been exhausted.
317- taskHandle .done ().whenComplete ((__ , t ) -> wip .remove (taskHandle .id ()));
324+ taskHandle .done ().whenComplete ((__ , t ) -> {
325+ if (t != null ) {
326+ numberOfErrors ++;
327+ }
328+ wip .remove (taskHandle .id ());
329+ });
318330
319331 queue .put (taskHandle );
320332 return taskHandle ;
321333 }
322334
335+ /**
336+ * Get the current tally of failed tasks.
337+ * An object is only considered failed if it can no longer be retried.
338+ */
339+ public int numberOfErrors () {
340+ return numberOfErrors ;
341+ }
342+
323343 void start () {
324344 if (closed ) {
325345 throw new IllegalStateException ("context is closed" );
0 commit comments