Class: WorkerKiller::Middleware
- Inherits:
-
Object
- Object
- WorkerKiller::Middleware
- Defined in:
- lib/worker_killer/middleware.rb
Direct Known Subclasses
Defined Under Namespace
Classes: OOMLimiter, RequestsLimiter
Instance Attribute Summary collapse
-
#inhibitions ⇒ Object
readonly
Returns the value of attribute inhibitions.
-
#interval ⇒ Object
readonly
Returns the value of attribute interval.
-
#killer ⇒ Object
readonly
Returns the value of attribute killer.
-
#limiter ⇒ Object
readonly
Returns the value of attribute limiter.
-
#reaction ⇒ Object
readonly
Returns the value of attribute reaction.
Instance Method Summary collapse
- #call(env) ⇒ Object
- #call_with_inhibition(env, path_info, &after) ⇒ Object
- #default_kill(l, k) ⇒ Object
- #inihibit(_path_info) ⇒ Object
-
#initialize(app, killer:, klass:, interval: 10, inhibitions: [], reaction: nil, **opts) ⇒ Middleware
constructor
inhibitions - список адресов, которые будут времнно блокировать перезапуск воркеров: Rails.application.config.middleware.insert_before( Rack::Sendfile, WorkerKiller::Middleware::RequestsLimiter, killer:, min: 2, max: 3, inhibitions: [‘/test’] ).
- #logger ⇒ Object
- #react ⇒ Object
- #release ⇒ Object
- #wrap_rack_response_body(rack_response_body, &after) ⇒ Object
Constructor Details
#initialize(app, killer:, klass:, interval: 10, inhibitions: [], reaction: nil, **opts) ⇒ Middleware
inhibitions - список адресов, которые будут времнно блокировать перезапуск воркеров: Rails.application.config.middleware.insert_before(
Rack::Sendfile,
WorkerKiller::Middleware::RequestsLimiter, killer:, min: 2, max: 3, inhibitions: ['/test']
)
15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/worker_killer/middleware.rb', line 15 def initialize(app, killer:, klass:, interval: 10, inhibitions: [], reaction: nil, **opts) @app = app @killer = killer @interval = interval @inhibitions = inhibitions.dup.freeze @reaction = reaction || method(:default_kill) @limiter = klass.new(**opts) @last_reacted_at = 0.0 @inhibited = 0 @delayed_reaction = nil end |
Instance Attribute Details
#inhibitions ⇒ Object (readonly)
Returns the value of attribute inhibitions.
7 8 9 |
# File 'lib/worker_killer/middleware.rb', line 7 def inhibitions @inhibitions end |
#interval ⇒ Object (readonly)
Returns the value of attribute interval.
7 8 9 |
# File 'lib/worker_killer/middleware.rb', line 7 def interval @interval end |
#killer ⇒ Object (readonly)
Returns the value of attribute killer.
7 8 9 |
# File 'lib/worker_killer/middleware.rb', line 7 def killer @killer end |
#limiter ⇒ Object (readonly)
Returns the value of attribute limiter.
7 8 9 |
# File 'lib/worker_killer/middleware.rb', line 7 def limiter @limiter end |
#reaction ⇒ Object (readonly)
Returns the value of attribute reaction.
7 8 9 |
# File 'lib/worker_killer/middleware.rb', line 7 def reaction @reaction end |
Instance Method Details
#call(env) ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/worker_killer/middleware.rb', line 30 def call(env) if (path_info = env['PATH_INFO']) && inhibitions.any?{|i| path_info[i] } call_with_inhibition(env, path_info) do # реакция будет вызвана после реального окончания обработки react if limiter.check end else @app.call(env).tap do # реакция будет вызвана сейчас (как обычно) react if limiter.check end end end |
#call_with_inhibition(env, path_info, &after) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/worker_killer/middleware.rb', line 44 def call_with_inhibition(env, path_info, &after) inihibit(path_info) rack_response = nil begin rack_response = @app.call(env) rescue Exception # в случае ошибоки во время @app.call возращаем как было release raise end # Почему именно each описано в спецификации в разделе The Response # https://github.com/rack/rack/blob/main/SPEC.rdoc if rack_response[2].respond_to?(:each) rack_response[2] = wrap_rack_response_body(rack_response[2], &after) else release # освобождаем сразу after.call end rack_response end |
#default_kill(l, k) ⇒ Object
92 93 94 |
# File 'lib/worker_killer/middleware.rb', line 92 def default_kill(l, k) k.kill(l.started_at) end |
#inihibit(_path_info) ⇒ Object
96 97 98 |
# File 'lib/worker_killer/middleware.rb', line 96 def inihibit(_path_info) @inhibited += 1 end |
#logger ⇒ Object
109 110 111 |
# File 'lib/worker_killer/middleware.rb', line 109 def logger @logger ||= WorkerKiller.configuration.logger end |
#react ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/worker_killer/middleware.rb', line 80 def react now = Process.clock_gettime(Process::CLOCK_MONOTONIC) return if now - @last_reacted_at < @interval @last_reacted_at = now if @inhibited > 0 @delayed_reaction = -> { reaction.call(limiter, killer) } else reaction.call(limiter, killer) end end |
#release ⇒ Object
100 101 102 103 104 105 106 107 |
# File 'lib/worker_killer/middleware.rb', line 100 def release return unless ((@inhibited -= 1) == 0) && @delayed_reaction @delayed_reaction.tap do |cb| @delayed_reaction = nil cb.call end end |
#wrap_rack_response_body(rack_response_body, &after) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/worker_killer/middleware.rb', line 68 def wrap_rack_response_body(rack_response_body, &after) Enumerator.new do |y| rack_response_body.each {|chunk| y << chunk } # Почему именно close описано в спецификации в разделе The Response # https://github.com/rack/rack/blob/main/SPEC.rdoc rack_response_body.close if rack_response_body.respond_to?(:close) release # освобождаем после отправки всего тела after.call end end |