Class: ShipengineLtlTrackingWorker

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

Overview

Hourly poll of ShipEngine's LTL tracking endpoint for every invoiced
ShipEngine LTL freight delivery that has a PRO and hasn't delivered yet.

ShipEngine LTL has no tracking webhook (unlike ShipEngine parcel), so we
poll. Each poll projects the carrier's scans into ShipmentEvent rows keyed
by the delivery's PRO — the SAME table the parcel tracking webhook writes —
so the delivery-level status icon (DeliveriesHelper#shipengine_ltl_status_icon)
is rendered by the identical ShipmentEventStatusSummary logic as parcel.

The tracker is chosen per delivery by Shipping::ShipengineLtlTracker.for:
ShipEngine returns no scans at all for Roadrunner, so those deliveries read
the carrier's own tracking page via Shipping::RoadrunnerTracker and land in
the same table, indistinguishable downstream.

Stop conditions (see Shipping::ShipengineLtlTracker#pollable?):

  • a delivered scan (DE/SP) is on file → stop;
  • Shipping::ShipengineLtlTracker::POLL_MAX_AGE past pickup → stop (the
    backstop for refused / undeliverable / stuck freight; exceptions still
    surface via the red icon while polling continues up to the backstop).

Scheduled hourly via sidekiq-scheduler — see
config/sidekiq_production_schedule.yml and config/sidekiq_staging_schedule.yml.

Instance Method Summary collapse

Instance Method Details

#performObject

Runs the job.

Returns:

  • (Object)

    the result



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'app/workers/shipengine_ltl_tracking_worker.rb', line 33

def perform
  polled = 0
  inserted = 0

  Shipping::ShipengineLtlTracker.candidates.find_each do |delivery|
    # .for, not .new — ShipEngine returns no scans at all for some LTL
    # carriers, which get a carrier-specific tracker (Roadrunner).
    tracker = Shipping::ShipengineLtlTracker.for(delivery)
    next unless tracker.pollable?

    polled += 1
    inserted += tracker.poll!
  rescue StandardError => e
    # One bad delivery must not abort the sweep. The tracker already
    # swallows its own poll/persist errors, but guard the loop too.
    Rails.logger.error("[ShipengineLtlTrackingWorker] delivery=#{delivery.id} error: #{e.class}: #{e.message}")
    ErrorReporting.warning('ShipengineLtlTrackingWorker per-delivery failure',
                           error: e.message, delivery_id: delivery.id)
  end

  Rails.logger.info("[ShipengineLtlTrackingWorker] polled=#{polled} new_events=#{inserted}")
end