Class: AdSpendDayFinalizer

Inherits:
Object
  • Object
show all
Defined in:
app/workers/ad_spend_day_finalizer.rb

Overview

Fan-in for AdSpendSyncWorker's per-provider batch: decides what a day's
outcome means once every provider job has finished.

This is the part a hand-rolled chain cannot do well. Previously the day's
providers ran sequentially inside one job so "are we done?" was just the
method returning; fanned out, the answer only exists when the last child
lands — which is exactly what a Sidekiq Pro batch callback reports.

Three outcomes:

  • every provider succeeded → mark the day complete and, when this is part
    of a backfill, advance the chain to the next day;
  • a provider was throttled (gate open) → leave the day unmarked and come
    back to the SAME day once the cohort-wide cooldown expires;
  • a provider failed for another reason → leave the day unmarked and let the
    backfill move on, so one bad provider can't stall the whole range.

Instance Method Summary collapse

Instance Method Details

#on_complete(status, options) ⇒ void

This method returns an undefined value.

Parameters:

  • status (Sidekiq::Batch::Status)
  • options (Hash)

    what AdSpendSyncWorker registered with the batch

Options Hash (options):

  • :date (String)

    the ISO day this batch covered

  • :backfill_end (String, nil)

    last date of the range being
    walked, nil for a one-off run such as the nightly

  • :providers (Array<String>, nil)

    the run's provider scope,
    nil when every provider ran



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'app/workers/ad_spend_day_finalizer.rb', line 27

def on_complete(status, options)
  date = Date.parse(options['date'])
  backfill_end = options['backfill_end']
  providers = options['providers']
  scope = AdSpendSyncWorker.scope_for(providers)

  # Ordering matters: the in-flight claim is released by each branch only
  # AFTER it has recorded the outcome. Releasing first would leave a window
  # where the day is neither in flight nor complete, and a chain observing
  # that gap would dispatch a duplicate batch for a day that just finished.
  #
  # The cooldown only applies to a run that included Amazon — it is the only
  # provider that opens the gate, so standing a Google-only day down for one
  # would stall a backfill on someone else's quota.
  if AdSpendSyncWorker.throttleable?(providers) && Marketing::AdSpend::RunState.cooldown_active?
    handle_throttled(date, backfill_end, providers, scope)
  elsif status.failures.zero?
    handle_success(date, backfill_end, providers, scope)
  else
    handle_failures(status, date, backfill_end, providers, scope)
  end
end