package com.twitter.common.metrics; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; import com.google.common.base.Preconditions; import com.twitter.common.quantity.Amount; import com.twitter.common.quantity.Time; import com.twitter.common.util.concurrent.ExecutorServiceShutdown; /** * A fixed-rate poller that triggers a {@link MetricSampler}. */ public class MetricPoller { private static final Logger LOG = Logger.getLogger(MetricPoller.class.getName()); private static final Amount<Long, Time> SHUTDOWN_GRACE_PERIOD = Amount.of(2L, Time.SECONDS); private final MetricSampler sampler; private final ScheduledExecutorService executor; private final AtomicBoolean started = new AtomicBoolean(false); private final AtomicBoolean stopped = new AtomicBoolean(false); /** * Creates a new metric poller. * * @param sampler Sampler to fetch metric values from. * @param executor Executor service to run the sampler with. */ public MetricPoller(MetricSampler sampler, ScheduledExecutorService executor) { this.sampler = Preconditions.checkNotNull(sampler); this.executor = Preconditions.checkNotNull(executor); } /** * Initiates the poller. * The poller may only be started once. If an attempt is made to start a poller when it is * already started, {@link IllegalStateException} will be thrown. * * @param pollInterval Fixed poll rate. */ public void start(Amount<Long, Time> pollInterval) { Preconditions.checkNotNull(pollInterval); Preconditions.checkArgument(pollInterval.getValue() > 0, "Poll interval must be positive"); Preconditions.checkState(started.compareAndSet(false, true), "Poller is already started."); long pollIntervalMs = pollInterval.as(Time.MILLISECONDS); executor.scheduleAtFixedRate(sampler, pollIntervalMs, pollIntervalMs, TimeUnit.MILLISECONDS); } /** * Stops the poller. * If the poller is already stopped, or is in the process of being stopped, subsequent calls will * throw {@link IllegalStateException}. */ public void stop() { if (stopped.compareAndSet(false, true)) { new ExecutorServiceShutdown(executor, SHUTDOWN_GRACE_PERIOD).execute(); } else { LOG.warning("Poller is already stopped, subsequent calls ignored."); } } }