Class: AmazonAdsCampaignSyncWorker

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

Overview

Sidekiq worker: syncs Amazon Ads campaigns into the sources table once a day.

Direct parallel to PinterestCampaignSyncWorker / MicrosoftAdsCampaignSyncWorker,
except campaigns are bucketed per profile segment — seller vs vendor,
US vs CA — under the "Amazon Ads" node (itself under "Amazon", Source 195):

Amazon > Amazon Ads
├─ Amazon Seller US (nightly)
├─ Amazon Seller CA (nightly)
├─ Amazon Vendor US (initial sync only — Vendor Central is being wound down)
└─ Amazon Vendor CA (initial sync only)

The scheduled run syncs seller segments only. Vendor segments are populated
on demand via AmazonAdsCampaignSyncWorker.perform_async(true) and are
otherwise left untouched (their buckets are never archive-swept by a
seller-only run). Every enabled or paused campaign gets a 1:1 Source
under its segment bucket; campaigns that disappear are mirrored by setting
visibility: :archived rather than destroying the row.

Unlike the web ad platforms, Amazon Ads traffic lands on amazon.com listings
— never on warmlyyours.com — so campaign Sources deliberately carry no
utm_source/utm_medium: they must not swallow organic amazon.com referral
visits. The rows serve as the campaign registry in the Sources tree.

Scheduled at 02:15 America/Chicago daily — after Google (01:00), OpenAI
(01:15), Pinterest (01:30), Facebook (01:45) and Microsoft (02:00) so the
API ceilings don't compete for the same window.

Authenticates via AmazonAds::OauthService (OAuth 2.0, auto-refreshing) —
when the ad account hasn't been connected yet the worker logs and skips
rather than raising, so an unconnected integration never floods AppSignal.

See Also:

Constant Summary collapse

AMAZON_PARENT_SOURCE_ID =

Existing "Amazon" source — Retailers > Amazon (Source 195).

195
ADS_ROOT_NAME =

The ads grouping node under "Amazon"; the four segment buckets hang off it.

'Amazon Ads'
SEGMENTS =

Profile segments and their Source buckets. ongoing: false segments
(Vendor Central, on the way out) are skipped by the scheduled run and
only synced when perform(true) is invoked explicitly.

[
  { type: 'seller', country: 'US', parent_name: 'Amazon Seller US', ongoing: true },
  { type: 'seller', country: 'CA', parent_name: 'Amazon Seller CA', ongoing: true },
  { type: 'vendor', country: 'US', parent_name: 'Amazon Vendor US', ongoing: false },
  { type: 'vendor', country: 'CA', parent_name: 'Amazon Vendor CA', ongoing: false }
].freeze
ACTIVE_STATUSES =

Normalized campaign states that should appear as active Source records.
Paused campaigns stay visible (they resume without churn — the Pinterest
convention); anything else, or a campaign missing from the API result,
maps to Source#visibility = :archived.

%w[ENABLED PAUSED].freeze

Instance Method Summary collapse

Instance Method Details

#perform(include_vendor = false) ⇒ void

This method returns an undefined value.

Parameters:

  • include_vendor (Boolean) (defaults to: false)

    also sync the vendor segments (one-time /
    on-demand only; the schedule and admin button run seller-only)



67
68
69
70
71
72
73
74
75
76
77
# File 'app/workers/amazon_ads_campaign_sync_worker.rb', line 67

def perform(include_vendor = false)
  unless AmazonAds::OauthService.new.connected?
    logger.info 'AmazonAdsCampaignSyncWorker: Amazon Ads OAuth not connected — skipping. ' \
                'Connect the ad account at /amazon_ads/oauth/authorize.'
    return
  end

  Source.with_advisory_lock('amazon_ads_campaign_sync', timeout_seconds: 10) do
    sync_all(include_vendor)
  end
end