Class: AdSpendProviderSyncWorker

Inherits:
Object
  • Object
show all
Includes:
Sidekiq::Job
Defined in:
app/workers/ad_spend_provider_sync_worker.rb

Overview

Syncs ONE provider's spend for ONE day. Fanned out by AdSpendSyncWorker
inside a Sidekiq Pro batch, one job per provider.

The point of the split is retry granularity, not raw speed: Amazon dominates
a day's wall-clock, so running the four providers in parallel saves only a
minute. What it does buy is that an Amazon failure retries Amazon alone —
previously the whole day failed and a re-run re-fetched Google, Microsoft and
OpenAI too, spending their quota to recover someone else's.

Constant Summary collapse

MAX_REQUEST_AGE =

Constant.

2.hours
METRICS =

Adapter row key → source_metric_type enum value.

Marketing::AdSpend::Recorder::METRICS
METRIC_KEYS =

Constant.

Marketing::AdSpend::Recorder::METRIC_KEYS

Instance Method Summary collapse

Instance Method Details

#perform(provider, date_string, batch_id = nil, amazon_state = {}) ⇒ void

This method returns an undefined value.

Runs the job.

Parameters:

  • provider (String)
  • date_string (String)

    ISO date

  • batch_id (String, nil) (defaults to: nil)

    groups a day's rows for archival

  • amazon_state (Hash) (defaults to: {})

    the amazon state



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/workers/ad_spend_provider_sync_worker.rb', line 31

def perform(provider, date_string, batch_id = nil, amazon_state = {})
  adapter = AdSpendSyncWorker::ADAPTERS.fetch(provider)
  date = Date.parse(date_string)

  if provider == Marketing::AdSpend::AmazonAdapter::PROVIDER
    amazon_reports = Array(amazon_state[:reports])
    request_started_at = amazon_state[:started_at].presence || Time.current.iso8601
    request_attempt = (amazon_state[:attempt] || 1).to_i
    ensure_amazon_request_not_expired!(request_started_at)
    dispatch_amazon_reports(date, batch_id, amazon_reports)
  else
    record(adapter, adapter.call(date), date, batch_id)
  end
rescue Marketing::AdSpend::AmazonAdapter::ReportsThrottledError => e
  Marketing::AdSpend::RunState.open_cooldown!
  delay = Marketing::AdSpend::RunState.cooldown_remaining.seconds
  schedule_amazon_request(
    provider, date_string, batch_id, e.reports, request_started_at, request_attempt + 1, delay
  )
  Rails.logger.warn(
    "[AdSpendProviderSyncWorker] #{provider} #{date_string} request #{request_attempt} backing off " \
    "with #{e.reports.size} report(s): #{e.message}"
  )
rescue AmazonAds::ApiClient::ThrottledError => e
  # Report creation failed fast instead of sleeping. Opening the cohort gate
  # leaves the day unmarked; a backfill finalizer or self-heal run comes back
  # after quota has recovered.
  Marketing::AdSpend::RunState.open_cooldown!
  Rails.logger.warn("[AdSpendProviderSyncWorker] #{provider} #{date_string} backing off: #{e.message}")
end