Skip to content

Instantly share code, notes, and snippets.

@rosa
Last active August 24, 2024 20:06
Show Gist options
  • Save rosa/ca8fde4bee5a2734dc3a31c89c3d26cd to your computer and use it in GitHub Desktop.
Save rosa/ca8fde4bee5a2734dc3a31c89c3d26cd to your computer and use it in GitHub Desktop.
Puma plugin for Solid Queue
# 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