module Rack # Ensures only 1 thread passes through the stack the first time (subsequent requests are allowed through concurrently). # This is needed to work-around the thread-safety issue in http_router gem used by Padrino which results in a # DoubleCompileError when concurrent requests occur on server startup. # class SerialInitializer @@mutex = Mutex.new @@initialized = false def initialize(app) logger.info "SerialInitializer: #{Thread.current} created" @app = app end def call(env) if !@@initialized logger.info "SerialInitializer: #{Thread.current} not initialized, attempting lock" @@mutex.synchronize do logger.info "SerialInitializer: #{Thread.current} acquired lock!" if !@@initialized begin logger.info "SerialInitializer: #{Thread.current} within lock, app not initialized, going ahead with call" res = @app.call(env) @@initialized = true logger.info "SerialInitializer: #{Thread.current} app initialized successfully - this should only happen once!" return res rescue Exception => e logger.error "SerialInitializer: #{Thread.current} error initializing app, logging and re-raising (subsequent threads will re-attempt initialization): #{e.class} #{e.message} \n #{e.backtrace.join("\n")}" raise end else logger.info "SerialInitializer: #{Thread.current} acquired lock, but app was already initialized, calling it" return @app.call(env) end end else return @app.call(env) end end end end