Class LazyScheduler
ScheduledExecutorService owned by one class.
Centralizes the "volatile field + synchronized ensure-started + Workers
shutdown" pattern that every reporter and the orphan-flush path previously duplicated. Each
owner declares a static final LazyScheduler whose executor is created on first
getOrStart() call and torn down by stop() during UI stop or extension unload;
a subsequent getOrStart() transparently recreates a fresh executor, preserving the
existing lazy-restart contract.
Instances are thread-safe: start and stop serialize on the instance monitor, the backing
reference is volatile so peek() and isStarted() observe the most
recent write without locking, and stop() delegates to Workers so shutdown
semantics match every other extension-owned worker.
This helper does not clear reporter-specific state such as pushed-key sets or once-logged
flags; owners remain responsible for resetting their own session state in their own
stop() method after calling stop().
-
Constructor Summary
ConstructorsConstructorDescriptionLazyScheduler(String threadName) Creates a new holder with thedefault shutdown budget.LazyScheduler(String threadName, long shutdownTimeoutMs) Creates a new holder configured with the daemon thread name and shutdown budget to use. -
Method Summary
Modifier and TypeMethodDescriptionReturns the backing scheduler, creating the daemon executor on first call.booleanReturnstruewhen an executor is currently held.peek()Returns the current scheduler ornullwhen not started.booleanstartRecurring(Runnable task, long initialDelay, long period, TimeUnit unit) Schedules a recurring task on the backing scheduler if one has not been registered yet.voidstop()Null-swaps the backing reference under the holder's lock and hands the old executor toWorkers.awaitExecutorShutdown(java.util.concurrent.ExecutorService, long).
-
Constructor Details
-
LazyScheduler
Creates a new holder with thedefault shutdown budget.Preferred for owners that want the standard lazy-start/deterministic-stop behavior without specifying a custom teardown window.
- Parameters:
threadName- daemon thread name assigned to the scheduler's single worker thread
-
LazyScheduler
Creates a new holder configured with the daemon thread name and shutdown budget to use.- Parameters:
threadName- daemon thread name assigned to the scheduler's single worker threadshutdownTimeoutMs- maximum millisecondsstop()waits for termination before returning; forwarded toWorkers.awaitExecutorShutdown(java.util.concurrent.ExecutorService, long)
-
-
Method Details
-
getOrStart
Returns the backing scheduler, creating the daemon executor on first call.Synchronized so the executor and its daemon thread are instantiated at most once per lazy-start cycle even under concurrent callers. Callers may schedule or submit work against the returned reference directly.
- Returns:
- the active scheduler owned by this holder
-
startRecurring
Schedules a recurring task on the backing scheduler if one has not been registered yet.Folds the "
volatilecheck +synchronizeddouble-check +getOrStart().scheduleAtFixedRate(...)" idiom that every recurring reporter previously inlined. Safe to call from any thread and safe to call more than once: on the second and subsequent calls the method returnsfalsewithout touching the executor, so callers can treat it as idempotent.The start check uses
isStarted()rather than tracking the individual schedule, so callers that need to register multiple recurring tasks against the same holder must obtain the executor directly viagetOrStart()instead.- Parameters:
task- recurring work; scheduled viaScheduledExecutorService.scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit)initialDelay- delay before the first run, expressed inunitperiod- fixed-rate period between successive runs, expressed inunitunit- time unit forinitialDelayandperiod- Returns:
truewhen this call started the executor and registered the task;falsewhen the holder was already started and the call was a no-op
-
isStarted
public boolean isStarted()Returnstruewhen an executor is currently held.Intended for idempotent "already started?" guards that want to skip re-registering a recurring task. The check is lock-free because
executorisvolatile.- Returns:
truewhengetOrStart()has been called since the laststop(), otherwisefalse
-
peek
Returns the current scheduler ornullwhen not started.Primarily intended for tests and for owners like
ExporterIndexStatsReporterthat need to compare executor identity across recreation.- Returns:
- the active scheduler, or
nullwhen the holder has not been started (or has been stopped)
-
stop
public void stop()Null-swaps the backing reference under the holder's lock and hands the old executor toWorkers.awaitExecutorShutdown(java.util.concurrent.ExecutorService, long).Safe to call from any thread and safe to call more than once. A subsequent
getOrStart()creates a fresh executor. If shutdown does not complete within the configured timeout, the current thread's interrupt flag is restored; otherwise returns without throwing.
-