Puma's "rack.after_reply" integration for your Rack- and Rails-applications. Provides #call-able reply
abstraction and configurable non-threaded/threaded invocation flow with before/on_error/after hooks for each added reply.
Table of Contents
- Requirements
- Installation
- Usage
- Algorithm
- Configuration
- Adding replies
- Some debugging methods
- Test environments
 
- Contributing
- License
- Authors
Requirements
[back to top]
- 
concurrent-ruby(~> 1.3)
Installation
[back to top]
gem 'puma_after_reply'bundle install
# --- or ---
gem install puma_after_replyrequire 'puma_after_reply'Usage
[back to top]
- Algorithm
- Configuration
- Adding replies
- Some debugging methods
- Test environments
Algorithm
- every Puma's worker gets own reply collector;
- during the Puma's request your logic adds replies to the worker's reply collector:
- using PumaAfterReply.add_reply(doc);
- using PumaAfterReply.cond_reply(doc);
 
- using 
- after processing the request, Puma's worker returns a response to the browser;
- then Puma's worker launches accumulated replies:
- threaded replies are launched in separated threads;
- non-threaded replies are launched sequentially;
 
- after processing all replies, the worker's reply collector is cleared;
Each separated reply is launched according to the following invocation flow:
- 
before_reply hook (config.before_reply);
- reply invocation (reply.call);
- if reply.callfailed with an error:- 
log_error hook (config.log_error);
- 
on_error hook (config.on_error);
- 
raise_on_error fail check (config.fail_on_error)
 
- 
log_error hook (
- (ensure): after_reply hook (config.after_reply);
Remember: if you add a reply outside of the Puma's/Rack's request context your reply will never be processed and flushed (that can lead to the memory leak/memory bloat).
Configuration
[back to top]
PumaAfterReply.configure do |config|
  # default values:
  config.fail_on_error = false # expects: <Boolean>
  config.log_error = nil # expects: <nil,#call,Proc> (receives: error object)
  config.on_error = nil # expects: <nil,#call,Proc> (receives: error object)
  config.before_reply = nil # expects: <nil,#call,Proc> (receives: nothing)
  config.after_reply = nil # expects: <nil,#call,Proc> (receives: nothing)
  config.run_anyway = false # expects: <Boolean>
  config.thread_pool_size = 10 # expects: <Integer>
end
# get configs as a hash:
PumaAfterReply.cofnig.to_h
# get configs directly:
PumaAfterRepy.config.fail_on_error # and etc;# (IMPORTANT): register the middleware (Rails example)
Rails.configuration.middleware.use(PumaAfterReply::Middleware)Adding replies (add_reply/cond_reply)
[back to top]
- non-threaded way (this reply will be processed sequentially):
# non-threaded way:
PumaAfterReply.add_reply { your_code }- threaded-way (this reply will be processed in a separated thread):
# threaded way:
PumaAfterReply.add_reply(threaded: true) { your_code }- conditional reply adding:
- 
reply(condition, threaded: false, &reply)(threaded: falseby default);
- when condition is true- your reply will be pushed to the reply queue;
- when condition is false- your reply will be processed immediately;
- condition can be represented as callable object (#call/Proc);
 
- 
# with a boolean value:
PumaAfterReply.cond_reply(!Rails.env.test?) { your_code }# with a callabale value:
is_puma_request = proc { check_that_we_are_inside_a_request }
PumaAfterReply.cond_reply(is_puma_request) { your_code }# add threaded reply:
PumaAfterReply.cond_reply(some_condition, threaded: true) { your_code }Some debugging methods
[back to top]
# the count of the added replies:
PumaAfterReply.count # or .size# replies collections:
PumaAfterReply.replies # all added replies
PumaAfterReply.inline_replies # all added non-threaded replies
PumaAfterReply.threaded_replies # all added threaded replies# manual replies running:
PumaAfterReply.call # or .run# clear replies collector:
PumaAfterReply.clear# reset configs to default values:
PumaAfterReply.config.__reset!Test environments (and other Rack apps)
[back to top]
In some cases and Rack applications you can have no "rack.after_reply" key in your Rack env
(request environments in your tests, for example). For this cases you can use config.run_anyway = true:
on each of your rack request all accumulated replies will be processed and cleared in the same way as for Puma.
Contributing
[back to top]
- Fork it ( https://github.com/0exp/puma_after_reply )
- Create your feature branch (git checkout -b feature/my-new-feature)
- Commit your changes (git commit -am '[feature_context] Add some feature')
- Push to the branch (git push origin feature/my-new-feature)
- Create new Pull Request
License
[back to top]
Released under MIT License.
Authors
[back to top]