23
23
* An abstract class that builds an index incrementally. A background job can be launched using {@link #maybeTriggerAsyncJob(long)},
24
24
* it will create the index from the source index up to the last complete bucket that is allowed to be built (based on job position).
25
25
* Only one background job can run simultaneously and {@link #onFinish} is called when the job
26
- * finishes. {@link #onStop()} is called after the current search returns when the job is stopped early via a call
27
- * to {@link #stop()}. {@link #onFailure(Exception)} is called if the job fails with an exception and {@link #onAbort()}
26
+ * finishes before state is persisted. The indexer can be stopped early by a call to {@link #stop()} which will
27
+ * trigger the {@link #onStopping()} and {@link #onStopped()} methods.
28
+ * {@link #onFailure(Exception)} is called if the job fails with an exception and {@link #onAbort()}
28
29
* is called if the indexer is aborted while a job is running. The indexer must be started ({@link #start()}
29
30
* to allow a background job to run when {@link #maybeTriggerAsyncJob(long)} is called.
30
- * {@link #stop()} can be used to stop the background job without aborting the indexer.
31
31
*
32
32
* In a nutshell this is a 2 cycle engine: 1st it sends a query, 2nd it indexes documents based on the response, sends the next query,
33
33
* indexes, queries, indexes, ... until a condition lets the engine pause until the source provides new input.
@@ -87,10 +87,10 @@ public synchronized IndexerState start() {
87
87
88
88
/**
89
89
* Sets the internal state to {@link IndexerState#STOPPING} if an async job is
90
- * running in the background, {@link #onStop ()} will be called when the background job
90
+ * running in the background, {@link #onStopped ()} will be called when the background job
91
91
* detects that the indexer is stopped.
92
92
* If there is no job running when this function is called the returned
93
- * state is {@link IndexerState#STOPPED} and {@link #onStop ()} will not be called.
93
+ * state is {@link IndexerState#STOPPED} and {@link #onStopped ()} will not be called.
94
94
*
95
95
* @return The new state for the indexer (STOPPED, STOPPING or ABORTING if the job was already aborted).
96
96
*/
@@ -249,20 +249,30 @@ public synchronized boolean maybeTriggerAsyncJob(long now) {
249
249
250
250
/**
251
251
* Called when a background job finishes before the internal state changes from {@link IndexerState#INDEXING} back to
252
- * {@link IndexerState#STARTED}.
252
+ * {@link IndexerState#STARTED} and before {@link #doSaveState(IndexerState, Object, Runnable)} is called
253
253
*
254
254
* @param listener listener to call after done
255
255
*/
256
256
protected abstract void onFinish (ActionListener <Void > listener );
257
257
258
+
258
259
/**
259
- * Called when the indexer is stopped. This is only called when the indexer is stopped
260
- * via {@link #stop()} as opposed to {@link #onFinish(ActionListener)} which is called
261
- * when the indexer's work is done.
260
+ * Called when a background job stops after internal state has changed from {@link IndexerState#STOPPING}
261
+ * to {@link IndexerState#STOPPED} and before state is persisted via {@link #doSaveState(IndexerState, Object, Runnable)}.
262
+ * This is only called when the indexer is stopped due to a call to {@link #stop()}
262
263
*/
263
- protected void onStop () {
264
+ protected void onStopping () {
264
265
}
265
266
267
+ /**
268
+ * Called when the indexer is stopped after {@link #onStopping()} and {@link #doSaveState(IndexerState, Object, Runnable)}
269
+ * have been called.
270
+ */
271
+ protected void onStopped () {
272
+ }
273
+
274
+
275
+
266
276
/**
267
277
* Called when a background job detects that the indexer is aborted causing the
268
278
* async execution to stop.
@@ -280,16 +290,18 @@ private void finishWithIndexingFailure(Exception exc) {
280
290
}
281
291
282
292
private IndexerState finishAndSetState () {
283
- AtomicBoolean callOnStop = new AtomicBoolean (false );
284
- AtomicBoolean callOnAbort = new AtomicBoolean (false );
293
+ AtomicBoolean callOnStopping = new AtomicBoolean ();
294
+ AtomicBoolean callOnAbort = new AtomicBoolean ();
285
295
IndexerState updatedState = state .updateAndGet (prev -> {
296
+ callOnAbort .set (false );
297
+ callOnStopping .set (false );
286
298
switch (prev ) {
287
299
case INDEXING :
288
300
// ready for another job
289
301
return IndexerState .STARTED ;
290
302
291
303
case STOPPING :
292
- callOnStop .set (true );
304
+ callOnStopping .set (true );
293
305
// must be started again
294
306
return IndexerState .STOPPED ;
295
307
@@ -311,8 +323,8 @@ private IndexerState finishAndSetState() {
311
323
}
312
324
});
313
325
314
- if (callOnStop .get ()) {
315
- onStop ();
326
+ if (callOnStopping .get ()) {
327
+ onStopping ();
316
328
} else if (callOnAbort .get ()) {
317
329
onAbort ();
318
330
}
@@ -412,7 +424,7 @@ private boolean checkState(IndexerState currentState) {
412
424
413
425
case STOPPING :
414
426
logger .info ("Indexer job encountered [" + IndexerState .STOPPING + "] state, halting indexer." );
415
- doSaveState (finishAndSetState (), getPosition (), () -> {} );
427
+ doSaveState (finishAndSetState (), getPosition (), this :: onStopped );
416
428
return false ;
417
429
418
430
case STOPPED :
0 commit comments