package de.spinscale.elasticsearch.service.suggest; import de.spinscale.elasticsearch.action.suggest.refresh.SuggestRefreshRequest; import de.spinscale.elasticsearch.action.suggest.refresh.TransportSuggestRefreshAction; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.cluster.ClusterService; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.StopWatch; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.component.Lifecycle; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.index.service.IndexService; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.service.IndexShard; import org.elasticsearch.indices.IndicesLifecycle; import org.elasticsearch.indices.IndicesService; import java.util.Iterator; public class SuggestService extends AbstractLifecycleComponent<SuggestService> { private final TimeValue suggestRefreshInterval; private final boolean suggestRefreshDisabled; private volatile Thread suggestUpdaterThread; private volatile boolean closed; private final TransportSuggestRefreshAction suggestRefreshAction; private final ClusterService clusterService; private final IndicesService indicesService; @Inject public SuggestService(Settings settings, TransportSuggestRefreshAction suggestRefreshAction, ClusterService clusterService, IndicesService indicesService) { super(settings); this.suggestRefreshAction = suggestRefreshAction; this.clusterService = clusterService; this.indicesService = indicesService; suggestRefreshDisabled = settings.getAsBoolean("suggest.refresh_disabled", false); suggestRefreshInterval = settings.getAsTime("suggest.refresh_interval", TimeValue.timeValueMinutes(10)); } @Override protected void doStart() throws ElasticsearchException { if (suggestRefreshDisabled) { logger.info("Suggest component started with out refreshing automatically"); } else { suggestUpdaterThread = EsExecutors.daemonThreadFactory(settings, "suggest_updater").newThread(new SuggestUpdaterThread()); suggestUpdaterThread.start(); logger.info("Suggest component started with refresh interval [{}]", suggestRefreshInterval); } // When the instance is shut down or the index is deleted indicesService.indicesLifecycle().addListener(new IndicesLifecycle.Listener() { @Override public void beforeIndexClosed(IndexService indexService) { for (Iterator<IndexShard> shardServiceIterator = indexService.iterator(); shardServiceIterator.hasNext(); ) { IndexShard indexShard = shardServiceIterator.next(); ShardSuggestService suggestShardService = indexService.shardInjectorSafe(indexShard.shardId().id()).getInstance(ShardSuggestService.class); suggestShardService.shutDown(); } } }); // when the shard is deleted (or moved to another cluster instance) // using this in the above case fails, because i cannot get the indexService anymore at beforeIndexShardClosed() indicesService.indicesLifecycle().addListener(new IndicesLifecycle.Listener() { @Override public void beforeIndexShardClosed(ShardId shardId, @Nullable IndexShard indexShard) { IndexService indexService = indicesService.indexService(shardId.index().name()); if (indexService != null) { ShardSuggestService suggestShardService = indexService.shardInjectorSafe(shardId.id()).getInstance(ShardSuggestService.class); suggestShardService.shutDown(); } } }); } @Override protected void doClose() throws ElasticsearchException { if (closed) { return; } closed = true; if (suggestUpdaterThread != null) { suggestUpdaterThread.interrupt(); } logger.info("Suggest component stopped"); } @Override protected void doStop() throws ElasticsearchException {} public class SuggestUpdaterThread implements Runnable { @Override public void run() { while (!closed) { DiscoveryNode node = clusterService.localNode(); boolean isClusterStarted = clusterService.lifecycleState().equals(Lifecycle.State.STARTED); if (isClusterStarted && node != null && node.isMasterNode()) { StopWatch sw = new StopWatch().start(); suggestRefreshAction.execute(new SuggestRefreshRequest()).actionGet(); logger.info("Suggest update took [{}], next update in [{}]", sw.stop().totalTime(), suggestRefreshInterval); } else { if (node != null) { logger.debug("[{}]/[{}] is not master node, not triggering update", node.getId(), node.getName()); } } try { Thread.sleep(suggestRefreshInterval.millis()); } catch (InterruptedException e1) { continue; } } } } }