Class: Shipping::TrackingResync

Inherits:
BaseService show all
Defined in:
app/services/shipping/tracking_resync.rb

Overview

Polls ShipEngine's tracking endpoint for one Shipment or external RMA
tracking number and feeds the
response through WebhookProcessors::ShipengineProcessor exactly as if
ShipEngine had pushed it — so scans land in shipment_events and the
roll-up columns on shipments update through the single code path that
already handles dedup, idempotency, and state.

Two callers:

  • ShipmentTrackingRegistrationWorker at registration time, because
    tracking.start only subscribes to FUTURE callbacks — scans that
    already happened are never pushed.
  • ShipmentsTrackingWorker as the self-heal pass, because a
    subscription that goes quiet mid-transit is otherwise invisible: we
    keep waiting for a push that never comes. Observed 2026-07-27 —
    7 of 13 parcels on the warehouse Problematic Deliveries tab had been
    delivered for up to two days, ShipEngine's API knew, and no webhook
    ever carried the delivered scan.

Defined Under Namespace

Classes: Result

Instance Attribute Summary

Attributes inherited from BaseService

#options

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseService

#log_debug, #log_error, #log_info, #log_warning, #logger, #process, #tagged_logger

Constructor Details

#initialize(resource, tracking_number: nil, carrier: nil) ⇒ TrackingResync

Returns a new instance of TrackingResync.

Parameters:

  • resource (Shipment, Rma)
  • tracking_number (String, nil) (defaults to: nil)

    explicit number for resources such
    as Rma that own a collection instead of one scalar number

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

    explicit carrier for external RMA numbers



46
47
48
49
50
51
# File 'app/services/shipping/tracking_resync.rb', line 46

def initialize(resource, tracking_number: nil, carrier: nil)
  super()
  @resource = resource
  @tracking_number = tracking_number.presence || resource.try(:tracking_number)
  @carrier = carrier.presence || resource.try(:carrier)
end

Class Method Details

.callObject



40
# File 'app/services/shipping/tracking_resync.rb', line 40

def self.call(...) = new(...).call

Instance Method Details

#callResult

Returns:



54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/services/shipping/tracking_resync.rb', line 54

def call
  return Result.new(skipped_reason: :no_tracking_number) if @tracking_number.blank?

  shipengine_code = resolve_shipengine_code
  return Result.new(skipped_reason: :no_shipengine_code) unless shipengine_code

  tracking = fetch_tracking_history(shipengine_code, @tracking_number)
  events = tracking[:events] || tracking['events'] || []
  return Result.new(skipped_reason: :no_events) if events.empty?

  Result.new(events: events.size, webhook_log: ingest_and_process!(tracking, shipengine_code, events.size))
end