Last active
August 24, 2024 20:06
-
-
Save rosa/ca8fde4bee5a2734dc3a31c89c3d26cd to your computer and use it in GitHub Desktop.
Puma plugin for Solid Queue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A plugin you can use if you want to run the Solid Queue's supervisor together with Puma and have Puma monitor | |
# and manage it. You just need to copy the plugin to lib/puma/plugin/solid_queue.rb and then add | |
# plugin :solid_queue | |
# to your `puma.rb` configuration. | |
# | |
# By default, the Puma plugin will fork additional processes for each worker and dispatcher so that they run in | |
# different processes. This provides the best isolation and performance, but can have additional memory usage. | |
# Alternatively, workers and dispatchers can be run within the same Puma process(s). To do so just | |
# configure the plugin as: | |
# | |
# plugin :solid_queue | |
# solid_queue_mode :async | |
# | |
# Note that in this case, the `processes` configuration option will be ignored. | |
# | |
require "puma/plugin" | |
module Puma | |
class DSL | |
def solid_queue_mode(mode = :fork) | |
@options[:solid_queue_mode] = mode.to_sym | |
end | |
end | |
end | |
Puma::Plugin.create do | |
attr_reader :puma_pid, :solid_queue_pid, :log_writer, :solid_queue_supervisor | |
def start(launcher) | |
@log_writer = launcher.log_writer | |
@puma_pid = $$ | |
if launcher.options[:solid_queue_mode] == :async | |
start_async(launcher) | |
else | |
start_forked(launcher) | |
end | |
end | |
private | |
def start_forked(launcher) | |
in_background do | |
monitor_solid_queue | |
end | |
launcher.events.on_booted do | |
@solid_queue_pid = fork do | |
Thread.new { monitor_puma } | |
SolidQueue::Supervisor.start(mode: :fork) | |
end | |
end | |
launcher.events.on_stopped { stop_solid_queue } | |
launcher.events.on_restart { stop_solid_queue } | |
end | |
def start_async(launcher) | |
launcher.events.on_booted { @solid_queue_supervisor = SolidQueue::Supervisor.start(mode: :async) } | |
launcher.events.on_stopped { solid_queue_supervisor.stop } | |
launcher.events.on_restart { solid_queue_supervisor.stop; solid_queue_supervisor.start } | |
end | |
def stop_solid_queue | |
Process.waitpid(solid_queue_pid, Process::WNOHANG) | |
log "Stopping Solid Queue..." | |
Process.kill(:INT, solid_queue_pid) if solid_queue_pid | |
Process.wait(solid_queue_pid) | |
rescue Errno::ECHILD, Errno::ESRCH | |
end | |
def monitor_puma | |
monitor(:puma_dead?, "Detected Puma has gone away, stopping Solid Queue...") | |
end | |
def monitor_solid_queue | |
monitor(:solid_queue_dead?, "Detected Solid Queue has gone away, stopping Puma...") | |
end | |
def monitor(process_dead, message) | |
loop do | |
if send(process_dead) | |
log message | |
Process.kill(:INT, $$) | |
break | |
end | |
sleep 2 | |
end | |
end | |
def solid_queue_dead? | |
if solid_queue_started? | |
Process.waitpid(solid_queue_pid, Process::WNOHANG) | |
end | |
false | |
rescue Errno::ECHILD, Errno::ESRCH | |
true | |
end | |
def solid_queue_started? | |
solid_queue_pid.present? | |
end | |
def puma_dead? | |
Process.ppid != puma_pid | |
end | |
def log(...) | |
log_writer.log(...) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment