Class: Solrengine::Sdp::TrackTransferJob

Inherits:
ActiveJob::Base
  • Object
show all
Defined in:
app/jobs/solrengine/sdp/track_transfer_job.rb

Overview

Settles every Transfer row into a terminal state (R6). Two modes, keyed on the row’s status:

processing/confirmed → poll get_transfer, map per the status table,
  re-enqueue until terminal. A row stuck in processing past
  Configuration#expired_transfer_deadline settles as engine-local
  "expired" (SDP has no such status). confirmed keeps tracking —
  it is user-facing success, but finalized is the terminal verdict.

unknown (the create POST read-timed out, the row never got an SDP id,
  or SDP 404ed the id we had) → reconcile: scan the source wallet's
  transfers for the engine memo token. Found → adopt the SDP row and
  keep tracking; not found → re-enqueue and scan again until the
  deadline settles it as failed "unsent (reconcile exhausted)".

Deadline exhaustion is checked at the top of perform, BEFORE any SDP I/O, so an SDP outage can never keep a row unsettled past its deadline (an in-poll check would only fire after a successful GET).

API errors never orphan a row (mirrors ProvisionWalletJob’s posture): Unavailable/Timeout propagate to retry_on; NotFound flips the row to “unknown” so the memo token — not a 404 poll loop — decides; any other Sdp::Error re-enqueues within the deadline and settles the row failed (message renderable) past it.

Backoff: a simple fixed wait (Configuration#transfer_poll_interval, default 3s) rather than exponential — Solana confirmation latency is bounded at seconds, and expired_transfer_deadline caps total tracking, so growing waits would only delay the verdict.

Inherits ActiveJob::Base directly so the engine never depends on the host app’s ApplicationJob (same posture as ProvisionWalletJob).

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.poll_intervalObject



54
55
56
# File 'app/jobs/solrengine/sdp/track_transfer_job.rb', line 54

def self.poll_interval
  Solrengine::Sdp.configuration.transfer_poll_interval.seconds
end

Instance Method Details

#perform(transfer) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'app/jobs/solrengine/sdp/track_transfer_job.rb', line 58

def perform(transfer)
  return if transfer.terminal?
  return if settle_past_deadline(transfer)

  if transfer.unknown?
    reconcile(transfer)
  else
    poll(transfer)
  end
rescue ::Sdp::Unavailable, ::Sdp::Timeout
  raise # transport: retry_on owns backoff and the exhaustion handoff
rescue ::Sdp::NotFound
  # The id provably doesn't exist at SDP — polling it would 404
  # forever. Reconcile by memo token instead: it positively identifies
  # OUR attempt (found → adopt; never found → the deadline settles
  # the row as unsent).
  transfer.update!(status: "unknown")
  reenqueue(transfer)
rescue ::Sdp::Error => e
  # Auth/rate-limit/validation errors must never strand the row in a
  # dead-letter: within the deadline they read as an API hiccup —
  # re-enqueue and try again; past it the row settles failed with the
  # renderable reason.
  if past_deadline?(transfer)
    transfer.settle!("failed", sdp_error: e.message)
  else
    reenqueue(transfer)
  end
end