Dopo un EOF SMTP passa al destinatario successivo invece di congelare la coda.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
class Mailings::OutboundQueue
|
class Mailings::OutboundQueue
|
||||||
LOCK_PATH = Rails.root.join("tmp/outbound_smtp.lock")
|
LOCK_PATH = Rails.root.join("tmp/outbound_smtp.lock")
|
||||||
STAMP_PATH = Rails.root.join("tmp/outbound_last_sent")
|
STAMP_PATH = Rails.root.join("tmp/outbound_last_sent")
|
||||||
|
ATTEMPT_PATH = Rails.root.join("tmp/outbound_last_attempt")
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
attr_accessor :min_interval
|
attr_accessor :min_interval, :fail_interval
|
||||||
|
|
||||||
def enqueue(recipient)
|
def enqueue(recipient)
|
||||||
recipient.with_lock do
|
recipient.with_lock do
|
||||||
@@ -29,7 +30,9 @@ class Mailings::OutboundQueue
|
|||||||
begin
|
begin
|
||||||
CampaignMailer.raise_delivery_errors = true
|
CampaignMailer.raise_delivery_errors = true
|
||||||
outcome = recipient.deliver_queued!
|
outcome = recipient.deliver_queued!
|
||||||
stamp!
|
stamp_attempt!
|
||||||
|
stamp! if outcome == :sent
|
||||||
|
Rails.logger.info("[outbound] #{outcome} mailing=#{recipient.mailing_id} to=#{recipient.email}")
|
||||||
outcome == :sent ? :sent : :deferred
|
outcome == :sent ? :sent : :deferred
|
||||||
ensure
|
ensure
|
||||||
CampaignMailer.raise_delivery_errors = false if Rails.env.development?
|
CampaignMailer.raise_delivery_errors = false if Rails.env.development?
|
||||||
@@ -45,7 +48,11 @@ class Mailings::OutboundQueue
|
|||||||
end
|
end
|
||||||
|
|
||||||
def next_queued
|
def next_queued
|
||||||
queued_scope.order(:updated_at, :id).first
|
queued_scope.order(
|
||||||
|
Arel.sql(
|
||||||
|
"CASE WHEN mailing_recipients.error_message IS NULL OR mailing_recipients.error_message = '' THEN 0 ELSE 1 END, mailing_recipients.updated_at ASC, mailing_recipients.id ASC"
|
||||||
|
)
|
||||||
|
).first
|
||||||
end
|
end
|
||||||
|
|
||||||
def queued_scope
|
def queued_scope
|
||||||
@@ -53,18 +60,17 @@ class Mailings::OutboundQueue
|
|||||||
end
|
end
|
||||||
|
|
||||||
def seconds_until_next_slot
|
def seconds_until_next_slot
|
||||||
return 0 if min_interval.to_f <= 0
|
[
|
||||||
|
remaining(last_sent_at, min_interval),
|
||||||
last = last_sent_at
|
remaining(last_attempt_at, fail_interval)
|
||||||
return 0 if last.nil?
|
].max
|
||||||
|
|
||||||
remaining = min_interval - (Time.current - last)
|
|
||||||
remaining.positive? ? remaining : 0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset!
|
def reset!
|
||||||
@last_sent_at = nil
|
@last_sent_at = nil
|
||||||
|
@last_attempt_at = nil
|
||||||
File.delete(stamp_path) if File.exist?(stamp_path)
|
File.delete(stamp_path) if File.exist?(stamp_path)
|
||||||
|
File.delete(attempt_path) if File.exist?(attempt_path)
|
||||||
rescue Errno::ENOENT
|
rescue Errno::ENOENT
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
@@ -74,17 +80,36 @@ class Mailings::OutboundQueue
|
|||||||
File.write(stamp_path, @last_sent_at.to_f.to_s)
|
File.write(stamp_path, @last_sent_at.to_f.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
def last_sent_at
|
def stamp_attempt!
|
||||||
return @last_sent_at if @last_sent_at
|
@last_attempt_at = Time.current
|
||||||
return unless File.exist?(stamp_path)
|
File.write(attempt_path, @last_attempt_at.to_f.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
@last_sent_at = Time.zone.at(Float(File.read(stamp_path)))
|
def last_sent_at
|
||||||
rescue ArgumentError, TypeError, Errno::ENOENT
|
@last_sent_at ||= read_time(stamp_path)
|
||||||
nil
|
end
|
||||||
|
|
||||||
|
def last_attempt_at
|
||||||
|
@last_attempt_at ||= read_time(attempt_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def remaining(timestamp, interval)
|
||||||
|
return 0 if interval.to_f <= 0 || timestamp.nil?
|
||||||
|
|
||||||
|
leftover = interval - (Time.current - timestamp)
|
||||||
|
leftover.positive? ? leftover : 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_time(path)
|
||||||
|
return unless File.exist?(path)
|
||||||
|
|
||||||
|
Time.zone.at(Float(File.read(path)))
|
||||||
|
rescue ArgumentError, TypeError, Errno::ENOENT
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
def lock_path
|
def lock_path
|
||||||
LOCK_PATH
|
LOCK_PATH
|
||||||
end
|
end
|
||||||
@@ -92,7 +117,12 @@ class Mailings::OutboundQueue
|
|||||||
def stamp_path
|
def stamp_path
|
||||||
STAMP_PATH
|
STAMP_PATH
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def attempt_path
|
||||||
|
ATTEMPT_PATH
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.min_interval = Rails.env.test? ? 0.0 : 180.0
|
self.min_interval = Rails.env.test? ? 0.0 : 60.0
|
||||||
|
self.fail_interval = Rails.env.test? ? 0.0 : 30.0
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class Mailings::OutboundQueueTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
setup do
|
setup do
|
||||||
Mailings::OutboundQueue.min_interval = 0
|
Mailings::OutboundQueue.min_interval = 0
|
||||||
|
Mailings::OutboundQueue.fail_interval = 0
|
||||||
Mailings::OutboundQueue.reset!
|
Mailings::OutboundQueue.reset!
|
||||||
Mailings::SmtpGate.min_gap = 0
|
Mailings::SmtpGate.min_gap = 0
|
||||||
Mailings::SmtpGate.backoff_base = 0
|
Mailings::SmtpGate.backoff_base = 0
|
||||||
@@ -13,6 +14,7 @@ class Mailings::OutboundQueueTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
Mailings::OutboundQueue.min_interval = 0
|
Mailings::OutboundQueue.min_interval = 0
|
||||||
|
Mailings::OutboundQueue.fail_interval = 0
|
||||||
Mailings::OutboundQueue.reset!
|
Mailings::OutboundQueue.reset!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user