5
5
*/
6
6
package org .elasticsearch .xpack .watcher ;
7
7
8
+ import org .apache .logging .log4j .LogManager ;
8
9
import org .apache .logging .log4j .Logger ;
9
10
import org .elasticsearch .action .ActionRequest ;
10
11
import org .elasticsearch .action .ActionResponse ;
12
+ import org .elasticsearch .action .bulk .BulkItemResponse ;
13
+ import org .elasticsearch .action .bulk .BulkProcessor ;
14
+ import org .elasticsearch .action .bulk .BulkRequest ;
15
+ import org .elasticsearch .action .bulk .BulkResponse ;
11
16
import org .elasticsearch .bootstrap .BootstrapCheck ;
12
17
import org .elasticsearch .client .Client ;
13
18
import org .elasticsearch .cluster .metadata .IndexNameExpressionResolver ;
20
25
import org .elasticsearch .common .inject .util .Providers ;
21
26
import org .elasticsearch .common .io .stream .NamedWriteableRegistry ;
22
27
import org .elasticsearch .common .logging .LoggerMessageFormat ;
23
- import org .elasticsearch .common .logging .Loggers ;
24
28
import org .elasticsearch .common .regex .Regex ;
25
29
import org .elasticsearch .common .settings .ClusterSettings ;
26
30
import org .elasticsearch .common .settings .IndexScopedSettings ;
27
31
import org .elasticsearch .common .settings .Setting ;
28
32
import org .elasticsearch .common .settings .Settings ;
29
33
import org .elasticsearch .common .settings .SettingsFilter ;
34
+ import org .elasticsearch .common .unit .ByteSizeUnit ;
35
+ import org .elasticsearch .common .unit .ByteSizeValue ;
30
36
import org .elasticsearch .common .unit .TimeValue ;
31
37
import org .elasticsearch .common .util .concurrent .EsExecutors ;
32
38
import org .elasticsearch .common .xcontent .NamedXContentRegistry ;
51
57
import org .elasticsearch .threadpool .FixedExecutorBuilder ;
52
58
import org .elasticsearch .threadpool .ThreadPool ;
53
59
import org .elasticsearch .watcher .ResourceWatcherService ;
60
+ import org .elasticsearch .xpack .core .ClientHelper ;
54
61
import org .elasticsearch .xpack .core .XPackPlugin ;
55
62
import org .elasticsearch .xpack .core .XPackSettings ;
56
63
import org .elasticsearch .xpack .core .ssl .SSLService ;
184
191
import java .util .List ;
185
192
import java .util .Map ;
186
193
import java .util .Set ;
194
+ import java .util .concurrent .TimeUnit ;
187
195
import java .util .function .Consumer ;
188
196
import java .util .function .Function ;
189
197
import java .util .function .Supplier ;
190
198
import java .util .function .UnaryOperator ;
199
+ import java .util .stream .Collectors ;
191
200
192
201
import static java .util .Collections .emptyList ;
202
+ import static org .elasticsearch .common .settings .Setting .Property .NodeScope ;
203
+ import static org .elasticsearch .xpack .core .ClientHelper .WATCHER_ORIGIN ;
193
204
194
205
public class Watcher extends Plugin implements ActionPlugin , ScriptPlugin , ReloadablePlugin {
195
206
@@ -201,6 +212,16 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa
201
212
Setting .boolSetting ("xpack.watcher.encrypt_sensitive_data" , false , Setting .Property .NodeScope );
202
213
public static final Setting <TimeValue > MAX_STOP_TIMEOUT_SETTING =
203
214
Setting .timeSetting ("xpack.watcher.stop.timeout" , TimeValue .timeValueSeconds (30 ), Setting .Property .NodeScope );
215
+ private static final Setting <Integer > SETTING_BULK_ACTIONS =
216
+ Setting .intSetting ("xpack.watcher.bulk.actions" , 1 , 1 , 10000 , NodeScope );
217
+ private static final Setting <Integer > SETTING_BULK_CONCURRENT_REQUESTS =
218
+ Setting .intSetting ("xpack.watcher.bulk.concurrent_requests" , 0 , 0 , 20 , NodeScope );
219
+ private static final Setting <TimeValue > SETTING_BULK_FLUSH_INTERVAL =
220
+ Setting .timeSetting ("xpack.watcher.bulk.flush_interval" , TimeValue .timeValueSeconds (1 ), NodeScope );
221
+ private static final Setting <ByteSizeValue > SETTING_BULK_SIZE =
222
+ Setting .byteSizeSetting ("xpack.watcher.bulk.size" , new ByteSizeValue (1 , ByteSizeUnit .MB ),
223
+ new ByteSizeValue (1 , ByteSizeUnit .MB ), new ByteSizeValue (10 , ByteSizeUnit .MB ), NodeScope );
224
+
204
225
205
226
public static final ScriptContext <SearchScript .Factory > SCRIPT_SEARCH_CONTEXT =
206
227
new ScriptContext <>("xpack" , SearchScript .Factory .class );
@@ -210,9 +231,10 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa
210
231
public static final ScriptContext <TemplateScript .Factory > SCRIPT_TEMPLATE_CONTEXT
211
232
= new ScriptContext <>("xpack_template" , TemplateScript .Factory .class );
212
233
213
- private static final Logger logger = Loggers .getLogger (Watcher .class );
234
+ private static final Logger logger = LogManager .getLogger (Watcher .class );
214
235
private WatcherIndexingListener listener ;
215
236
private HttpClient httpClient ;
237
+ private BulkProcessor bulkProcessor ;
216
238
217
239
protected final Settings settings ;
218
240
protected final boolean transportClient ;
@@ -318,7 +340,49 @@ public Collection<Object> createComponents(Client client, ClusterService cluster
318
340
final InputRegistry inputRegistry = new InputRegistry (settings , inputFactories );
319
341
inputFactories .put (ChainInput .TYPE , new ChainInputFactory (settings , inputRegistry ));
320
342
321
- final HistoryStore historyStore = new HistoryStore (settings , client );
343
+ bulkProcessor = BulkProcessor .builder (ClientHelper .clientWithOrigin (client , WATCHER_ORIGIN ), new BulkProcessor .Listener () {
344
+ @ Override
345
+ public void beforeBulk (long executionId , BulkRequest request ) {
346
+ }
347
+
348
+ @ Override
349
+ public void afterBulk (long executionId , BulkRequest request , BulkResponse response ) {
350
+ if (response .hasFailures ()) {
351
+ Map <String , String > triggeredWatches = Arrays .stream (response .getItems ())
352
+ .filter (BulkItemResponse ::isFailed )
353
+ .filter (r -> r .getIndex ().startsWith (TriggeredWatchStoreField .INDEX_NAME ))
354
+ .collect (Collectors .toMap (BulkItemResponse ::getId , BulkItemResponse ::getFailureMessage ));
355
+ if (triggeredWatches .isEmpty () == false ) {
356
+ String failure = triggeredWatches .values ().stream ().collect (Collectors .joining (", " ));
357
+ logger .error ("triggered watches could not be deleted {}, failure [{}]" ,
358
+ triggeredWatches .keySet (), Strings .substring (failure , 0 , 2000 ));
359
+ }
360
+
361
+ Map <String , String > overwrittenIds = Arrays .stream (response .getItems ())
362
+ .filter (BulkItemResponse ::isFailed )
363
+ .filter (r -> r .getIndex ().startsWith (HistoryStoreField .INDEX_PREFIX ))
364
+ .filter (r -> r .getVersion () > 1 )
365
+ .collect (Collectors .toMap (BulkItemResponse ::getId , BulkItemResponse ::getFailureMessage ));
366
+ if (overwrittenIds .isEmpty () == false ) {
367
+ String failure = overwrittenIds .values ().stream ().collect (Collectors .joining (", " ));
368
+ logger .info ("overwrote watch history entries {}, possible second execution of a triggered watch, failure [{}]" ,
369
+ overwrittenIds .keySet (), Strings .substring (failure , 0 , 2000 ));
370
+ }
371
+ }
372
+ }
373
+
374
+ @ Override
375
+ public void afterBulk (long executionId , BulkRequest request , Throwable failure ) {
376
+ logger .error ("error executing bulk" , failure );
377
+ }
378
+ })
379
+ .setFlushInterval (SETTING_BULK_FLUSH_INTERVAL .get (settings ))
380
+ .setBulkActions (SETTING_BULK_ACTIONS .get (settings ))
381
+ .setBulkSize (SETTING_BULK_SIZE .get (settings ))
382
+ .setConcurrentRequests (SETTING_BULK_CONCURRENT_REQUESTS .get (settings ))
383
+ .build ();
384
+
385
+ HistoryStore historyStore = new HistoryStore (settings , bulkProcessor );
322
386
323
387
// schedulers
324
388
final Set <Schedule .Parser > scheduleParsers = new HashSet <>();
@@ -340,7 +404,7 @@ public Collection<Object> createComponents(Client client, ClusterService cluster
340
404
final TriggerService triggerService = new TriggerService (settings , triggerEngines );
341
405
342
406
final TriggeredWatch .Parser triggeredWatchParser = new TriggeredWatch .Parser (settings , triggerService );
343
- final TriggeredWatchStore triggeredWatchStore = new TriggeredWatchStore (settings , client , triggeredWatchParser );
407
+ final TriggeredWatchStore triggeredWatchStore = new TriggeredWatchStore (settings , client , triggeredWatchParser , bulkProcessor );
344
408
345
409
final WatcherSearchTemplateService watcherSearchTemplateService =
346
410
new WatcherSearchTemplateService (settings , scriptService , xContentRegistry );
@@ -416,6 +480,12 @@ public List<Setting<?>> getSettings() {
416
480
settings .add (Setting .simpleString ("xpack.watcher.execution.scroll.timeout" , Setting .Property .NodeScope ));
417
481
settings .add (WatcherLifeCycleService .SETTING_REQUIRE_MANUAL_START );
418
482
483
+ // bulk processor configuration
484
+ settings .add (SETTING_BULK_ACTIONS );
485
+ settings .add (SETTING_BULK_CONCURRENT_REQUESTS );
486
+ settings .add (SETTING_BULK_FLUSH_INTERVAL );
487
+ settings .add (SETTING_BULK_SIZE );
488
+
419
489
// notification services
420
490
settings .addAll (SlackService .getSettings ());
421
491
settings .addAll (EmailService .getSettings ());
@@ -608,7 +678,15 @@ public List<ScriptContext<?>> getContexts() {
608
678
609
679
@ Override
610
680
public void close () throws IOException {
681
+ bulkProcessor .flush ();
611
682
IOUtils .closeWhileHandlingException (httpClient );
683
+ try {
684
+ if (bulkProcessor .awaitClose (10 , TimeUnit .SECONDS ) == false ) {
685
+ logger .warn ("failed to properly close watcher bulk processor" );
686
+ }
687
+ } catch (InterruptedException e ) {
688
+ Thread .currentThread ().interrupt ();
689
+ }
612
690
}
613
691
614
692
/**
0 commit comments