app/services/singleton_lifecycle.rb
Rama develop · réplica de lectura del repositorio original.
# Class-level lifecycle for a process-wide singleton background worker:
# start/stop/restart/running? plus the mutex-guarded accessors that keep at
# most one live instance alive at a time.
#
# `extend` this into a class. The class must provide `storage` — a
# Concurrent::Map living outside the autoload paths (defined in an initializer)
# so the singleton state survives code reloading in development.
#
# Shared by ManagedThread (single-thread workers like BackupScheduler) and by
# Orchestration::EventsListener, which runs its own multi-thread instance but
# reuses this exact singleton wiring. A class can override restart/stop_instance
# (EventsListener adds a restart cooldown) — its own definitions take
# precedence over the ones mixed in here.
module SingletonLifecycle
def start
class_mutex.synchronize { start_instance }
end
def stop
class_mutex.synchronize { stop_instance }
end
def restart
class_mutex.synchronize do
stop_instance
start_instance
end
end
def running?
instance&.running?
end
def class_mutex
storage[:mutex] ||= Mutex.new
end
private
# The Concurrent::Map holding the singleton's :mutex and :instance.
def storage
raise NotImplementedError, "#{self} must define `storage`"
end
def start_instance
return if instance&.running?
instance&.stop
new_instance = new
new_instance.start
self.instance = new_instance
end
def stop_instance
return unless instance
instance.stop
self.instance = nil
end
def instance
storage[:instance]
end
def instance=(value)
storage[:instance] = value
end
end