Class: Mizuno::Reloader
- Inherits:
-
Object
- Object
- Mizuno::Reloader
- Defined in:
- lib/mizuno/reloader.rb
Overview
Middleware for reloading production applications; works exactly like Rack::Reloader, but rather than checking for any changed file, only looks at one specific file.
Also allows for explicit reloading via a class method, as well as by sending a SIGHUP to the process.
Class Attribute Summary collapse
-
.logger ⇒ Object
Returns the value of attribute logger.
-
.reloaders ⇒ Object
Returns the value of attribute reloaders.
-
.trigger ⇒ Object
Returns the value of attribute trigger.
Class Method Summary collapse
Instance Method Summary collapse
-
#call(env) ⇒ Object
Reload @app on request.
-
#find(file, paths) ⇒ Object
Takes a relative or absolute
file
name, a couple possiblepaths
that thefile
might reside in. -
#find_files_for_reload ⇒ Object
Walk through the list of every file we’ve loaded.
-
#initialize(app, interval = 1) ⇒ Reloader
constructor
A new instance of Reloader.
-
#mtime(file) ⇒ Object
Returns the modification time of file.
-
#reload!(force = false) ⇒ Object
Reloads the application if (a) we haven’t reloaded in since our last check, and © some other thread hasn’t handled the update.
-
#verify(file) ⇒ Object
Returns true if the file is loadable; uses the wrapper functionality of Kernel#load to protect the global namespace.
Constructor Details
#initialize(app, interval = 1) ⇒ Reloader
Returns a new instance of Reloader.
34 35 36 37 38 39 40 41 |
# File 'lib/mizuno/reloader.rb', line 34 def initialize(app, interval = 1) Reloader.add(self) @app = app @interval = interval @trigger = self.class.trigger @logger = self.class.logger @updated = @threshold = Time.now.to_i end |
Class Attribute Details
.logger ⇒ Object
Returns the value of attribute logger.
20 21 22 |
# File 'lib/mizuno/reloader.rb', line 20 def logger @logger end |
.reloaders ⇒ Object
Returns the value of attribute reloaders.
20 21 22 |
# File 'lib/mizuno/reloader.rb', line 20 def reloaders @reloaders end |
.trigger ⇒ Object
Returns the value of attribute trigger.
20 21 22 |
# File 'lib/mizuno/reloader.rb', line 20 def trigger @trigger end |
Class Method Details
.add(reloader) ⇒ Object
27 28 29 30 31 32 |
# File 'lib/mizuno/reloader.rb', line 27 def Reloader.add(reloader) Thread.exclusive do @logger ||= Mizuno::Server.logger @reloaders << reloader end end |
.reload! ⇒ Object
23 24 25 |
# File 'lib/mizuno/reloader.rb', line 23 def Reloader.reload! reloaders.each { |r| r.reload!(true) } end |
Instance Method Details
#call(env) ⇒ Object
Reload @app on request.
46 47 48 49 |
# File 'lib/mizuno/reloader.rb', line 46 def call(env) Thread.exclusive { reload! } @app.call(env) end |
#find(file, paths) ⇒ Object
Takes a relative or absolute file
name, a couple possible paths
that the file
might reside in. Returns a tuple of the full path where the file was found and its modification time, or nil if not found.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/mizuno/reloader.rb', line 120 def find(file, paths) if(Pathname.new(file).absolute?) return unless ( = mtime(file)) @logger.debug("Found #{file}") [ file, ] else paths.each do |path| fullpath = File.((File.join(path, file))) next unless ( = mtime(fullpath)) @logger.debug("Found #{file} in #{fullpath}") return([ fullpath, ]) end return(nil) end end |
#find_files_for_reload ⇒ Object
Walk through the list of every file we’ve loaded.
91 92 93 94 95 96 97 |
# File 'lib/mizuno/reloader.rb', line 91 def find_files_for_reload paths = [ './', *$LOAD_PATH ].uniq [ $0, *$LOADED_FEATURES ].uniq.map do |file| next if file =~ /\.(so|bundle)$/ yield(find(file, paths)) end end |
#mtime(file) ⇒ Object
Returns the modification time of file.
139 140 141 142 143 144 145 146 147 |
# File 'lib/mizuno/reloader.rb', line 139 def mtime(file) begin return unless file stat = File.stat(file) stat.file? ? stat.mtime.to_i : nil rescue Errno::ENOENT, Errno::ENOTDIR, Errno::ESRCH nil end end |
#reload!(force = false) ⇒ Object
Reloads the application if (a) we haven’t reloaded in since our last check, and © some other thread hasn’t handled the update.
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 |
# File 'lib/mizuno/reloader.rb', line 57 def reload!(force = false) return unless (Time.now.to_i > @threshold) @threshold = Time.now.to_i + @interval return unless (force or \ (( = mtime(@trigger)).to_i > @updated)) ||= Time.now.to_i # Check updated files to ensure they're loadable. missing, errors = 0, 0 files = find_files_for_reload do |file, file_mtime| next(missing += 1 and nil) unless file_mtime next unless (file_mtime >= @updated) next(errors += 1 and nil) unless verify(file) file end # Cowardly fail if we can't load something. @logger.debug("#{missing} files missing during reload.") \ if (missing > 0) return(@logger.error("#{errors} errors, not reloading.")) \ if (errors > 0) # Reload everything that's changed. files.each do |file| next unless file @logger.info("Reloading #{file}") load(file) end @updated = end |
#verify(file) ⇒ Object
Returns true if the file is loadable; uses the wrapper functionality of Kernel#load to protect the global namespace.
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/mizuno/reloader.rb', line 103 def verify(file) begin @logger.debug("Verifying #{file}") load(file, true) return(true) rescue => error @logger.error("Failed to verify #{file}: #{error.to_s}") error.backtrace.each { |l| @logger.error(" #{l}") } end end |