Initial commit
This commit is contained in:
96
lib/daemons/amqp_daemon.rb
Normal file
96
lib/daemons/amqp_daemon.rb
Normal file
@@ -0,0 +1,96 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
ROOT = File.expand_path('../../..', __FILE__)
|
||||
|
||||
require File.join(ROOT, 'config', 'environment')
|
||||
|
||||
raise "bindings must be provided." if ARGV.size == 0
|
||||
|
||||
logger = Rails.logger
|
||||
|
||||
conn = Bunny.new AMQP::Config.connect
|
||||
conn.start
|
||||
|
||||
ch = conn.create_channel
|
||||
id = $0.split(':')[2]
|
||||
prefetch = AMQP::Config.channel(id)[:prefetch] || 0
|
||||
ch.prefetch(prefetch) if prefetch > 0
|
||||
logger.info { "Connected to AMQP broker (prefetch: #{prefetch > 0 ? prefetch : 'default'})" }
|
||||
|
||||
terminate = proc do
|
||||
# logger is forbidden in signal handling, just use puts here
|
||||
puts "Terminating threads .."
|
||||
ch.work_pool.kill
|
||||
puts "Stopped."
|
||||
end
|
||||
|
||||
at_exit { conn.close }
|
||||
|
||||
Signal.trap("INT", &terminate)
|
||||
Signal.trap("TERM", &terminate)
|
||||
|
||||
workers = []
|
||||
ARGV.each do |id|
|
||||
worker = AMQP::Config.binding_worker(id)
|
||||
queue = ch.queue *AMQP::Config.binding_queue(id)
|
||||
|
||||
if args = AMQP::Config.binding_exchange(id)
|
||||
x = ch.send *args
|
||||
|
||||
case args.first
|
||||
when 'direct'
|
||||
queue.bind x, routing_key: AMQP::Config.routing_key(id)
|
||||
when 'topic'
|
||||
AMQP::Config.topics(id).each do |topic|
|
||||
queue.bind x, routing_key: topic
|
||||
end
|
||||
else
|
||||
queue.bind x
|
||||
end
|
||||
end
|
||||
|
||||
clean_start = AMQP::Config.data[:binding][id][:clean_start]
|
||||
queue.purge if clean_start
|
||||
|
||||
# Enable manual acknowledge mode by setting manual_ack: true.
|
||||
queue.subscribe manual_ack: true do |delivery_info, metadata, payload|
|
||||
logger.info { "Received: #{payload}" }
|
||||
begin
|
||||
|
||||
# Invoke Worker#process with floating number of arguments.
|
||||
args = [JSON.parse(payload), metadata, delivery_info]
|
||||
arity = worker.method(:process).arity
|
||||
resized_args = arity < 0 ? args : args[0...arity]
|
||||
worker.process(*resized_args)
|
||||
|
||||
# Send confirmation to RabbitMQ that message has been successfully processed.
|
||||
# See http://rubybunny.info/articles/queues.html
|
||||
ch.ack(delivery_info.delivery_tag)
|
||||
|
||||
rescue StandardError => e
|
||||
|
||||
# Ask RabbitMQ to deliver message once again later.
|
||||
# See http://rubybunny.info/articles/queues.html
|
||||
ch.nack(delivery_info.delivery_tag, false, true)
|
||||
|
||||
if worker.is_db_connection_error?(e)
|
||||
logger.error(db: :unhealthy, message: e.message)
|
||||
exit(1)
|
||||
end
|
||||
|
||||
report_exception(e)
|
||||
end
|
||||
end
|
||||
|
||||
workers << worker
|
||||
end
|
||||
|
||||
%w(USR1 USR2).each do |signal|
|
||||
Signal.trap(signal) do
|
||||
puts "#{signal} received."
|
||||
handler = "on_#{signal.downcase}"
|
||||
workers.each {|w| w.send handler if w.respond_to?(handler) }
|
||||
end
|
||||
end
|
||||
|
||||
ch.work_pool.join
|
||||
113
lib/daemons/daemons.god
Normal file
113
lib/daemons/daemons.god
Normal file
@@ -0,0 +1,113 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
RAILS_ENV = ENV.fetch('RAILS_ENV', 'development')
|
||||
RAILS_ROOT = File.expand_path('../../..', __FILE__)
|
||||
|
||||
require 'shellwords'
|
||||
|
||||
# Create non-default log/daemons directory.
|
||||
require 'fileutils'
|
||||
FileUtils.mkdir_p "#{RAILS_ROOT}/log/daemons"
|
||||
|
||||
def daemon(name, options = {})
|
||||
God.watch do |w|
|
||||
command = "bundle exec ruby lib/daemons/#{options.fetch(:script)}"
|
||||
command += ' ' + options[:arguments].join(' ') if options.key?(:arguments)
|
||||
filesafe_name = name.gsub(/\W/, '_')
|
||||
|
||||
w.name = name
|
||||
w.start = command
|
||||
w.dir = RAILS_ROOT
|
||||
w.env = { 'RAILS_ENV' => RAILS_ENV, 'RAILS_ROOT' => RAILS_ROOT }
|
||||
|
||||
# Peatio has lot of dependencies which take some time to load ever on fast disks.
|
||||
# God, by default, doesn't wait before resuming normal monitoring operations.
|
||||
# So we need to adjust this variable so God will wait 10 seconds on start/restart operations.
|
||||
w.grace = 10.seconds
|
||||
|
||||
# God will send SIGTERM to the process and wait 10 seconds.
|
||||
# If process has still not exited it will be killed by sending SIGKILL.
|
||||
w.stop_signal = 'TERM'
|
||||
w.stop_timeout = 10.seconds
|
||||
|
||||
# God will always keep process running unless it was manually terminated.
|
||||
w.keepalive
|
||||
|
||||
# In production Docker environment logs go to /dev/stdout.
|
||||
if RAILS_ENV == 'production'
|
||||
w.log_cmd = "#{RAILS_ROOT}/bin/logger #{name.shellescape}"
|
||||
#
|
||||
# In non-production environment logs go to files.
|
||||
else
|
||||
w.log = "#{RAILS_ROOT}/log/daemons/#{filesafe_name}.log"
|
||||
end
|
||||
|
||||
# Allow customizations.
|
||||
yield(w) if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
daemon 'amqp:deposit_collection',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ deposit_collection ]
|
||||
|
||||
daemon 'amqp:deposit_collection_fees',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ deposit_collection_fees ]
|
||||
|
||||
daemon 'amqp:deposit_coin_address',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ deposit_coin_address ]
|
||||
|
||||
daemon 'amqp:influx_writer',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ influx_writer ]
|
||||
|
||||
daemon 'amqp:market_ticker',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ market_ticker ]
|
||||
|
||||
daemon 'amqp:matching',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ matching ]
|
||||
|
||||
daemon 'amqp:order_processor',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ order_processor ]
|
||||
|
||||
daemon 'amqp:pusher_market',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ pusher_market ]
|
||||
|
||||
daemon 'amqp:pusher_member',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ pusher_member ]
|
||||
|
||||
daemon 'amqp:trade_executor',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ trade_executor ]
|
||||
|
||||
daemon 'amqp:withdraw_coin',
|
||||
script: 'amqp_daemon.rb',
|
||||
arguments: %w[ withdraw_coin ]
|
||||
|
||||
daemon 'daemon:blockchain',
|
||||
script: 'daemons.rb',
|
||||
arguments: %w[ blockchain ]
|
||||
|
||||
daemon 'daemon:k',
|
||||
script: 'daemons.rb',
|
||||
arguments: %w[ k ]
|
||||
|
||||
daemon 'daemon:global_state',
|
||||
script: 'daemons.rb',
|
||||
arguments: %w[ global_state ]
|
||||
|
||||
daemon 'daemon:withdraw_audit',
|
||||
script: 'daemons.rb',
|
||||
arguments: %w[ withdraw_audit ]
|
||||
|
||||
daemon 'daemon:slave_book',
|
||||
script: 'daemons.rb',
|
||||
arguments: %w[ slave_book ]
|
||||
31
lib/daemons/daemons.rb
Normal file
31
lib/daemons/daemons.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
ROOT = File.expand_path('../../..', __FILE__)
|
||||
require File.join(ROOT, 'config', 'environment')
|
||||
# default in peatio image
|
||||
# require File.join(ENV.fetch('RAILS_ROOT'), 'config', 'environment')
|
||||
|
||||
raise "Worker name must be provided." if ARGV.size == 0
|
||||
|
||||
name = ARGV[0]
|
||||
worker = "Workers::Daemons::#{name.camelize}".constantize.new
|
||||
|
||||
terminate = proc do
|
||||
puts "Terminating worker .."
|
||||
worker.stop
|
||||
puts "Stopped."
|
||||
end
|
||||
|
||||
Signal.trap("INT", &terminate)
|
||||
Signal.trap("TERM", &terminate)
|
||||
|
||||
begin
|
||||
worker.run
|
||||
rescue StandardError => e
|
||||
if worker.is_db_connection_error?(e)
|
||||
logger.error(db: :unhealthy, message: e.message)
|
||||
raise e
|
||||
end
|
||||
|
||||
report_exception(e)
|
||||
end
|
||||
Reference in New Issue
Block a user