class RFlow
The RFlow
application.
Constants
- VERSION
The gem version.
Attributes
RFlow's configuration. @return [RFlow::Configuration]
RFlow's logger, whose message will be routed to logs as specified in the configuration. @return [RFlow::Logger]
RFlow's master node which oversees all the others. @return [RFlow::Master]
Public Class Methods
Start RFlow
running. This is the main programmatic entry point to the application. Pulls in the configuration, sets up logging, and starts the master note.
@param config_database_path [String] the path to the SQLite configuration database @param daemonize [boolean] true to fork and daemonize; false to run in the foreground
# File lib/rflow.rb, line 39 def self.run!(config_database_path = nil, daemonize = false) @config_database_path = config_database_path @daemonize = daemonize establish_configuration chdir_application_directory setup_logger start_master_node rescue SystemExit => e # Do nothing, just prevent a normal exit from causing an unsightly # error in the logs end
Private Class Methods
# File lib/rflow.rb, line 60 def self.chdir_application_directory # First change to the config db directory, which might hold # relative paths for the other files/directories Dir.chdir(File.dirname(@config_database_path)) if @config_database_path Dir.chdir configuration['rflow.application_directory_path'] end
# File lib/rflow.rb, line 84 def self.default_error_callback(error) RFlow.logger.error "Unhandled error on worker thread: #{error.class}: #{error.message}, because: #{error.backtrace}" end
Wrapped version of EM.defer that also fixes logging, releases AR connections, and catches exceptions that would otherwise propagate to the main thread magically
# File lib/rflow.rb, line 91 def self.defer(op = nil, callback = nil, errback = nil, &blk) context = RFlow.logger.clone_logging_context EM.defer(nil, callback, errback || method(:default_error_callback)) do begin RFlow.logger.apply_logging_context context (op || blk).call ensure ActiveRecord::Base.connection_pool.release_connection end end end
# File lib/rflow.rb, line 53 def self.establish_configuration @configuration = Configuration.new(@config_database_path) unless configuration['rflow.application_directory_path'] raise ArgumentError, 'Empty configuration database! Use a view/controller (such as the RubyDSL) to create a configuration' end end
Nice pretty wrapper method to help reduce direct dependencies on EM
# File lib/rflow.rb, line 80 def self.next_tick(pr = nil, &block) EM.next_tick(pr, &block) end
This ought to be in EM, but we'll put it here instead of monkey-patching
# File lib/rflow.rb, line 104 def self.next_tick_and_wait mutex = Mutex.new condition = ConditionVariable.new mutex.synchronize do # while locked... RFlow.next_tick do # schedule a job that will... mutex.synchronize do # grab the lock begin yield # do its thing... condition.signal # then wake us up when it's done... rescue condition.signal # even if the thing fails raise end end end condition.wait(mutex) # drop the mutex to allow the job to run end end
# File lib/rflow.rb, line 67 def self.setup_logger include_stdout = !@daemonize logger.reconfigure(configuration, include_stdout) end
# File lib/rflow.rb, line 72 def self.start_master_node RFlow.logger.info "#{configuration['rflow.application_name']} starting" @master = Master.new(configuration) master.daemonize! if @daemonize master.run! # blocks until EventMachine stops end