All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.split.engine.segments.RefreshableSegmentFetcher Maven / Gradle / Ivy

package io.split.engine.segments;

import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.split.engine.SDKReadinessGates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * A SegmentFetchers implementation that creates RefreshableSegmentFetcher instances.
 *
 * @author adil
 */
public class RefreshableSegmentFetcher implements Closeable, SegmentFetcher {
    private static final Logger _log = LoggerFactory.getLogger(RefreshableSegmentFetcher.class);

    private final SegmentChangeFetcher _segmentChangeFetcher;
    private final AtomicLong _refreshEveryNSeconds;

    private final Object _lock = new Object();
    private final ConcurrentMap _segmentFetchers = Maps.newConcurrentMap();
    private final ScheduledExecutorService _scheduledExecutorService;
    private final SDKReadinessGates _gates;


    public RefreshableSegmentFetcher(SegmentChangeFetcher segmentChangeFetcher, long refreshEveryNSeconds, int numThreads, SDKReadinessGates gates) {
        _segmentChangeFetcher = segmentChangeFetcher;
        checkNotNull(_segmentChangeFetcher);

        checkArgument(refreshEveryNSeconds >= 0L);
        _refreshEveryNSeconds = new AtomicLong(refreshEveryNSeconds);

        ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder();
        threadFactoryBuilder.setDaemon(true);
        threadFactoryBuilder.setNameFormat("split-segmentFetcher-" + "%d");
        _scheduledExecutorService = Executors.newScheduledThreadPool(numThreads, threadFactoryBuilder.build());

        _gates = gates;
        checkNotNull(_gates);
    }

    public RefreshableSegment segment(String segmentName) {
        RefreshableSegment segment = _segmentFetchers.get(segmentName);
        if (segment != null) {
            return segment;
        }

        // we are locking here since we wanna make sure that we create only ONE RefreableSegmentFetcher
        // per segment.
        synchronized (_lock) {
            // double check
            segment = _segmentFetchers.get(segmentName);
            if (segment != null) {
                return segment;
            }

            segment = RefreshableSegment.create(segmentName, _segmentChangeFetcher, _gates);

            _scheduledExecutorService.scheduleWithFixedDelay(segment, 0L, _refreshEveryNSeconds.get(), TimeUnit.SECONDS);

            _segmentFetchers.putIfAbsent(segmentName, segment);

            return segment;
        }
    }

    @Override
    public void close() {
        if (_scheduledExecutorService == null || _scheduledExecutorService.isShutdown()) {
            return;
        }
        _scheduledExecutorService.shutdown();
        try {
            if (!_scheduledExecutorService.awaitTermination(2L, TimeUnit.SECONDS)) { //optional *
                _log.info("Executor did not terminate in the specified time.");
                List droppedTasks = _scheduledExecutorService.shutdownNow(); //optional **
                _log.info("Executor was abruptly shut down. These tasks will not be executed: " + droppedTasks);
            }
        } catch (InterruptedException e) {
            // reset the interrupt.
            _log.error("Shutdown of SegmentFetchers was interrupted");
            Thread.currentThread().interrupt();
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy