class Spring::Application
Attributes
manager[R]
original_env[R]
spring_env[R]
watcher[R]
Public Class Methods
new(manager, original_env)
click to toggle source
# File lib/spring-jruby/application.rb, line 11 def initialize(manager, original_env) @manager = manager @original_env = original_env @spring_env = Env.new @mutex = Mutex.new @waiting = Set.new @preloaded = false @state = :initialized @interrupt = IO.pipe end
Public Instance Methods
app_env()
click to toggle source
# File lib/spring-jruby/application.rb, line 33 def app_env ENV['RAILS_ENV'] end
app_name()
click to toggle source
# File lib/spring-jruby/application.rb, line 37 def app_name spring_env.app_name end
connect_database()
click to toggle source
# File lib/spring-jruby/application.rb, line 248 def connect_database ActiveRecord::Base.establish_connection if active_record_configured? end
disconnect_database()
click to toggle source
# File lib/spring-jruby/application.rb, line 244 def disconnect_database ActiveRecord::Base.remove_connection if active_record_configured? end
exit()
click to toggle source
# File lib/spring-jruby/application.rb, line 211 def exit state :exiting manager.shutdown(:RDWR) exit_if_finished sleep end
exit_if_finished()
click to toggle source
# File lib/spring-jruby/application.rb, line 218 def exit_if_finished @mutex.synchronize { Kernel.exit if exiting? && @waiting.empty? } end
exiting?()
click to toggle source
# File lib/spring-jruby/application.rb, line 53 def exiting? @state == :exiting end
initialized?()
click to toggle source
# File lib/spring-jruby/application.rb, line 65 def initialized? @state == :initialized end
invoke_after_fork_callbacks()
click to toggle source
# File lib/spring-jruby/application.rb, line 233 def invoke_after_fork_callbacks Spring.after_fork_callbacks.each do |callback| callback.call end end
loaded_application_features()
click to toggle source
# File lib/spring-jruby/application.rb, line 239 def loaded_application_features root = Spring.application_root_path.to_s $LOADED_FEATURES.select { |f| f.start_with?(root) } end
log(message)
click to toggle source
# File lib/spring-jruby/application.rb, line 41 def log(message) spring_env.log "[application:#{app_env}] #{message}" end
preload()
click to toggle source
# File lib/spring-jruby/application.rb, line 75 def preload log "preloading app" begin require "spring-jruby/commands" ensure start_watcher end require Spring.application_root_path.join("config", "application") # config/environments/test.rb will have config.cache_classes = true. However # we want it to be false so that we can reload files. This is a hack to # override the effect of config.cache_classes = true. We can then actually # set config.cache_classes = false after loading the environment. Rails::Application.initializer :initialize_dependency_mechanism, group: :all do ActiveSupport::Dependencies.mechanism = :load end require Spring.application_root_path.join("config", "environment") @original_cache_classes = Rails.application.config.cache_classes Rails.application.config.cache_classes = false disconnect_database @preloaded = :success rescue Exception => e @preloaded = :failure watcher.add e.backtrace.map { |line| line.match(/^(.*)\:\d+\:in /)[1] } raise e unless initialized? ensure watcher.add loaded_application_features watcher.add Spring.gemfile, "#{Spring.gemfile}.lock" if defined?(Rails) && Rails.application watcher.add Rails.application.paths["config/initializers"] watcher.add Rails.application.paths["config/database"] if secrets_path = Rails.application.paths["config/secrets"] watcher.add secrets_path end end end
preload_failed?()
click to toggle source
# File lib/spring-jruby/application.rb, line 49 def preload_failed? @preloaded == :failure end
preloaded?()
click to toggle source
# File lib/spring-jruby/application.rb, line 45 def preloaded? @preloaded end
print_exception(stream, error)
click to toggle source
# File lib/spring-jruby/application.rb, line 271 def print_exception(stream, error) first, rest = error.backtrace.first, error.backtrace.drop(1) stream.puts("#{first}: #{error} (#{error.class})") rest.each { |line| stream.puts("\tfrom #{line}") } end
run()
click to toggle source
# File lib/spring-jruby/application.rb, line 119 def run state :running notify_manager_ready loop do IO.select [manager, @interrupt.first] if terminating? || watcher_stale? || preload_failed? exit else serve IOWrapper.recv_io(manager, UNIXSocket).to_io end end end
serve(client)
click to toggle source
# File lib/spring-jruby/application.rb, line 134 def serve(client) child_started = [false] log "got client" manager.puts stdout, stderr, stdin = streams = receive_streams(client) reopen_streams(streams) preload unless preloaded? args, env = JSON.load(client.read(client.gets.to_i)).values_at("args", "env") command = Spring.command(args.shift) connect_database setup command if Rails.application.reloaders.any?(&:updated?) ActionDispatch::Reloader.cleanup! ActionDispatch::Reloader.prepare! end fork_child(client, streams, child_started) { IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") } trap("TERM", "DEFAULT") ARGV.replace(args) $0 = command.exec_name # Delete all env vars which are unchanged from before spring started original_env.each { |k, v| ENV.delete k if ENV[k] == v } # Load in the current env vars, except those which *were* changed when spring started env.each { |k, v| ENV[k] ||= v } # requiring is faster, so if config.cache_classes was true in # the environment's config file, then we can respect that from # here on as we no longer need constant reloading. if @original_cache_classes ActiveSupport::Dependencies.mechanism = :require Rails.application.config.cache_classes = true end connect_database srand invoke_after_fork_callbacks shush_backtraces before_command command.call } rescue Exception => e Kernel.exit if exiting? && e.is_a?(SystemExit) log "exception: #{e}" manager.puts unless child_started[0] if streams && !e.is_a?(SystemExit) print_exception(stderr || STDERR, e) streams.each(&:close) end client.puts(1) if child_started[0] client.close end
setup(command)
click to toggle source
The command might need to require some files in the main process so that they are cached. For example a test command wants to load the helper file once and have it cached.
# File lib/spring-jruby/application.rb, line 227 def setup(command) if command.setup watcher.add loaded_application_features # loaded features may have changed end end
shush_backtraces()
click to toggle source
This feels very naughty
# File lib/spring-jruby/application.rb, line 253 def shush_backtraces Kernel.module_eval do old_raise = Kernel.method(:raise) remove_method :raise define_method :raise do |*args| begin old_raise.call(*args) ensure if $! lib = File.expand_path("..", __FILE__) $!.backtrace.reject! { |line| line.start_with?(lib) } end end end private :raise end end
start_watcher()
click to toggle source
# File lib/spring-jruby/application.rb, line 69 def start_watcher @watcher = Spring.watcher @watcher.on_stale { state! :watcher_stale } @watcher.start end
state(val)
click to toggle source
# File lib/spring-jruby/application.rb, line 22 def state(val) return if exiting? log "#{@state} -> #{val}" @state = val end
state!(val)
click to toggle source
# File lib/spring-jruby/application.rb, line 28 def state!(val) state val @interrupt.last.write "." end
terminate()
click to toggle source
# File lib/spring-jruby/application.rb, line 200 def terminate if exiting? # Ensure that we do not ignore subsequent termination attempts log "forced exit" @waiting.each { |pid| Process.kill("TERM", pid) } Kernel.exit else state! :terminating end end
terminating?()
click to toggle source
# File lib/spring-jruby/application.rb, line 57 def terminating? @state == :terminating end
watcher_stale?()
click to toggle source
# File lib/spring-jruby/application.rb, line 61 def watcher_stale? @state == :watcher_stale end
Private Instance Methods
active_record_configured?()
click to toggle source
# File lib/spring-jruby/application.rb, line 279 def active_record_configured? defined?(ActiveRecord::Base) && ActiveRecord::Base.configurations.any? end