1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
require 'logger'
require 'concurrent/synchronization'
module Concurrent
# Provides ability to add and remove handlers to be run at `Kernel#at_exit`, order is undefined.
# Each handler is executed at most once.
#
# @!visibility private
class AtExitImplementation < Synchronization::LockableObject
include Logger::Severity
def initialize(*args)
super()
synchronize { ns_initialize(*args) }
end
# Add a handler to be run at `Kernel#at_exit`
# @param [Object] handler_id optionally provide an id, if allready present, handler is replaced
# @yield the handler
# @return id of the handler
def add(handler_id = nil, &handler)
id = handler_id || handler.object_id
synchronize { @handlers[id] = handler }
id
end
# Delete a handler by handler_id
# @return [true, false]
def delete(handler_id)
!!synchronize { @handlers.delete handler_id }
end
# Is handler with handler_id rpesent?
# @return [true, false]
def handler?(handler_id)
synchronize { @handlers.key? handler_id }
end
# @return copy of the handlers
def handlers
synchronize { @handlers }.clone
end
# install `Kernel#at_exit` callback to execute added handlers
def install
synchronize do
@installed ||= begin
at_exit { runner }
true
end
self
end
end
# Will it run during `Kernel#at_exit`
def enabled?
synchronize { @enabled }
end
# Configure if it runs during `Kernel#at_exit`
def enabled=(value)
synchronize { @enabled = value }
end
# run the handlers manually
# @return ids of the handlers
def run
handlers, _ = synchronize { handlers, @handlers = @handlers, {} }
handlers.each do |_, handler|
begin
handler.call
rescue => error
Concurrent.global_logger.call(ERROR, error)
end
end
handlers.keys
end
private
def ns_initialize(enabled = true)
@handlers = {}
@enabled = enabled
end
def runner
run if synchronize { @enabled }
end
end
private_constant :AtExitImplementation
# @see AtExitImplementation
# @!visibility private
AtExit = AtExitImplementation.new.install
end
|