Class: EdiAmazonPendingFeedWorker

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

Overview

Hourly: delivers Amazon feeds that were BUILT and then deferred, rather than
leaving them to rot until the next daily flow.

The gap this closes. Amazon's flows run once a day (every_x_hour: 24), and
the partner loop hits the marketplaces in a fixed order. SP-API meters
createFeed per SELLER ACCOUNT, and the EU account admits exactly five before
it throttles — measured twice on 2026-08-05, fr/be/de/es/it through and
nl/pl/se 429'd on both the 00:00 inventory and 00:30 price runs, five
submissions inside sixteen seconds. Amazon sends no Retry-After on a 429, so
Edi::Amazon::FeedMessageSender#defer falls back to +1 hour — and nothing
ran at +1 hour
. The next attempt was the following midnight, where the same
three marketplaces were last in line again.

Deterministic, permanent starvation of exactly the trailing partners. That is
why nl/pl/se shipped no inventory or price feed between 2026-06-16 and
2026-08-04 while their neighbours were fine — see
doc/troubleshooting/MENARD_PLAYWRIGHT_OUTAGE_2026_07.md.

The retry machinery already existed and simply had no runner:
transmit_after is set by the deferral, EdiCommunicationLog.requiring_processing
already honours it, and the sender already skips anything still in its window.
This is the missing hourly pass, not new mechanism.

Sends only — it never builds a snapshot. That keeps the daily
should_execute_flow? gate the sole authority on WHAT gets generated, while
delivery retries at a cadence that can actually reach a one-hour deferral.
Edi::Amazon::FeedSubmissionBudget still applies, so a backlog cannot burst.

Scheduled hourly at :20 — see config/sidekiq_production_schedule.yml, between
the discontinue (:15) and price (:30) slots so a retry never lands in the same
minute as a fresh flow.

Constant Summary collapse

SENDERS =

Feed categories this drains, and the orchestrator method that sends each.
A partner with the feed disabled returns Edi::NullProcessor, whose #process
is a no-op, so no per-partner gating is needed here.

{
  'inventory_advice' => :inventory_message_sender,
  'price_advice' => :price_message_sender,
  'listing_feed_data' => :listing_message_feed_sender
}.freeze

Instance Method Summary collapse

Instance Method Details

#performvoid

This method returns an undefined value.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'app/workers/edi_amazon_pending_feed_worker.rb', line 49

def perform
  pending.each do |partner, category|
    orchestrator = Edi::Amazon::Orchestrator.new(partner.to_sym)
    next unless orchestrator.try(:active).to_b

    sent = orchestrator.public_send(SENDERS.fetch(category)).process
    Rails.logger.info "[EdiAmazonPendingFeedWorker] #{partner}/#{category}: " \
                      "retried #{Array(sent).size} deferred feed(s)"
  rescue StandardError => e
    # One partner's failure must not strand the rest of the backlog.
    ErrorReporting.error(e, source: :background, partner: partner, category: category,
                            message: "Pending Amazon feed retry failed for #{partner}/#{category}")
  end
end