~singpolyma/sgx-jmp

3b7abebd4df7b8508edd310704b098095c3e17a7 — Stephen Paul Weber 3 months ago 8a4e129
Allow the DB to notify us to bill a customer
3 files changed, 57 insertions(+), 5 deletions(-)

A lib/db_notification.rb
A lib/dummy_command.rb
M sgx_jmp.rb
A lib/db_notification.rb => lib/db_notification.rb +17 -0
@@ 0,0 1,17 @@
# frozen_string_literal: true

require_relative "dummy_command"

module DbNotification
	def self.for(notify, customer)
		case notify[:relname]
		when "low_balance"
			LowBalance.for(customer).then { |lb| lb.method(:notify!) }
		when "possible_renewal"
			Command.execution = DummyCommand.new(customer)
			BillPlanCommand.for(customer)
		else
			raise "Unknown notification: #{notify[:relname]}"
		end
	end
end

A lib/dummy_command.rb => lib/dummy_command.rb +17 -0
@@ 0,0 1,17 @@
# frozen_string_literal: true

class DummyCommand
	attr_reader :customer

	def initialize(customer)
		@customer = customer
	end

	def reply(*); end

	def finish(*); end

	def log
		::LOG
	end
end

M sgx_jmp.rb => sgx_jmp.rb +23 -5
@@ 81,6 81,8 @@ require_relative "lib/command_list"
require_relative "lib/customer"
require_relative "lib/customer_info_form"
require_relative "lib/customer_repo"
require_relative "lib/dummy_command"
require_relative "lib/db_notification"
require_relative "lib/electrum"
require_relative "lib/empty_repo"
require_relative "lib/expiring_lock"


@@ 178,10 180,27 @@ end

EM.error_handler(&method(:panic))

# Infer anything we might have been notified about while we were down
def catchup_notify(db)
	db.query("SELECT customer_id FROM balances WHERE balance < 5").each do |c|
		db.query("SELECT pg_notify('low_balance', $1)", c.values)
	end
	db.query(<<~SQL).each do |c|
		SELECT customer_id
		FROM customer_plans INNER JOIN balances USING (customer_id)
		WHERE expires_at < LOCALTIMESTAMP AND balance >= 5
	SQL
		db.query("SELECT pg_notify('possible_renewal', $1)", c.values)
	end
end

def poll_for_notify(db)
	db.wait_for_notify_defer.then { |notify|
		CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new).find(notify[:extra])
	}.then(&LowBalance.method(:for)).then(&:notify!).then {
		CustomerRepo
			.new(sgx_repo: Bwmsgsv2Repo.new)
			.find(notify[:extra])
			.then { |customer| DbNotification.for(notify, customer) }
	}.then(&:call).then {
		poll_for_notify(db)
	}.catch(&method(:panic))
end


@@ 208,9 227,8 @@ when_ready do

	DB.hold do |conn|
		conn.query("LISTEN low_balance")
		conn.query("SELECT customer_id FROM balances WHERE balance < 5").each do |c|
			conn.query("SELECT pg_notify('low_balance', $1)", c.values)
		end
		conn.query("LISTEN possible_renewal")
		catchup_notify(conn)
		poll_for_notify(conn)
	end