Class: Brut::FrontEnd::Middlewares::ReloadApp

Inherits:
Brut::FrontEnd::Middleware show all
Defined in:
lib/brut/front_end/middlewares/reload_app.rb

Overview

Reloads the app without requiring a restart. This should only be used in development. Every single request will trigger this.

Constant Summary collapse

LOCK =
Concurrent::ReadWriteLock.new

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ ReloadApp

Returns a new instance of ReloadApp.



4
5
6
# File 'lib/brut/front_end/middlewares/reload_app.rb', line 4

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object



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
# File 'lib/brut/front_end/middlewares/reload_app.rb', line 7

def call(env)
  path = env["PATH_INFO"].to_s
  dir = if path[0] == "/"
          path.split(/\//)[1]
        else
          path.split(/\//)[0]
        end
  reload = !["static","js","css","__brut"].include?(dir)
  if reload
    # We can only have one thread reloading stuff at a time, per process.
    # The ReadWriteLock achieves this.
    #
    # Here, if any thread is serving a request, THIS thread will wait here.
    # Once no other thread is serving a request, the write lock is acquired and a reload happens.
    Brut.container.instrumentation.span(self.class.name) do |span|
      LOCK.with_write_lock do
        span.add_event("lock acquired")
        begin
          Brut.container.zeitwerk_loader.reload
          span.add_event("Zeitwerk reloaded")
          Brut.container.routing.reload
          span.add_event("Routing reloaded")
          Brut.container.asset_path_resolver.reload
          span.add_event("Asset Path Resolver reloaded")
          Brut.container.reload
          span.add_event("Brut.container reloaded")
          ::I18n.reload!
          span.add_event("I18n reloaded")
        rescue => ex
          SemanticLogger[self.class].warn("Reload failed - your browser may not show you the latest code: #{ex.message}\n#{ex.backtrace}")
        end
      end
    end
    # If another thread has a write lock, we wait here so that the reload can complete before serving
    # the request.  If no thread has a write lock, THIS thread may proceed to serve the request,
    # as will any other thread that gets here.
    LOCK.with_read_lock do
      @app.call(env)
    end
  else
    Brut.container.instrumentation.add_event("Not reloading")
    @app.call(env)
  end
end