Change summary
lib/db_notification.rb | 17 +++++++++++++++++
lib/dummy_command.rb | 17 +++++++++++++++++
sgx_jmp.rb | 28 +++++++++++++++++++++++-----
3 files changed, 57 insertions(+), 5 deletions(-)
Detailed changes
@@ -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
@@ -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
@@ -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