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