Class: MaquinaNewsletters::SendBatchJob
- Inherits:
-
ApplicationJob
- Object
- ActiveJob::Base
- ApplicationJob
- MaquinaNewsletters::SendBatchJob
- Defined in:
- app/jobs/maquina_newsletters/send_batch_job.rb
Overview
Delivers one batch of a newsletter, then enqueues the next batch (a day later) or marks the newsletter sent. A single code path covers both “all-at-once” (batch_size == 0 → one batch with every recipient) and multi-batch sends (Sidecar A4 — Pattern A is cancelled, no companion job).
State ownership (Sidecar A1–A4, C3):
- batch 0 owns the scheduled → sending transition and recipients_count.
- each send is isolated so one bad address can't re-spam the batch on retry.
- a wholly-unrecoverable run marks the newsletter failed and re-raises.
Instance Method Summary collapse
Instance Method Details
#perform(newsletter_id, batch_index) ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'app/jobs/maquina_newsletters/send_batch_job.rb', line 14 def perform(, batch_index) = Newsletter.find() # Idempotent guard: a terminal newsletter is never re-sent (protects # against double-trigger, e.g. schedule + send-now firing together). return if .sent? || .failed? recipients = .resolved_recipients if batch_index.zero? .start_sending! if .scheduled? # A1 .update!(recipients_count: recipients.size) # A3 end batch = .recipient_batch(recipients, batch_index) # A4 failures = deliver_batch(, batch) # C3 # A2: an entire non-empty batch that wholly failed is unrecoverable. if batch.any? && failures == batch.size raise "MaquinaNewsletters::SendBatchJob: every delivery in batch " \ "#{batch_index} of newsletter #{} failed" end if .recipient_batch(recipients, batch_index + 1).any? self.class.set(wait: 1.day).perform_later(, batch_index + 1) else .mark_sent! end rescue => e # A2 &.mark_failed! raise e end |