Class: Solrengine::Sdp::ProvisionWalletJob
- Inherits:
-
ActiveJob::Base
- Object
- ActiveJob::Base
- Solrengine::Sdp::ProvisionWalletJob
- Defined in:
- app/jobs/solrengine/sdp/provision_wallet_job.rb
Overview
Provisions an SDP custody wallet for a WalletOwner row, driving the four-state machine: pending → provisioning → ready | failed.
Idempotent three ways:
1. The row is already ready → return immediately.
2. Optimistic claim: only the job that flips the row pending/failed →
provisioning proceeds; a duplicate concurrent job updates 0 rows
and returns without touching the network. A provisioning row whose
lease has lapsed (worker died between claim and settle) may be
taken over — see #claim.
3. Label adoption: when SDP already has a wallet labeled
"#{namespace}-user-#{id}" (a previous create succeeded but the
response was lost, e.g. a read timeout), adopt it instead of
creating a duplicate.
Failure posture:
- Transport errors (Unavailable/Timeout) retry with backoff; the claim
stays held across retries (see #claim). Exhaustion lands the row in
failed with the transport reason — never a silent dead-letter.
- ProviderCapabilityError (the FL-10 gate: local custody cannot create
per-user wallets) is terminal: failed immediately, with the
actionable "use a managed provider" message renderable to the app.
- Any other Sdp::Error is equally terminal — retrying auth/validation
bugs changes nothing; the reason is stored, not buried in logs.
Inherits ActiveJob::Base directly so the engine never depends on the host app’s ApplicationJob being defined or compatible.
Instance Method Summary collapse
-
#mark_provisioning_failed(user, reason) ⇒ Object
Settles the row in failed — but only when this job holds the claim (row is in provisioning), so a stale job can never clobber a row another job has since taken to ready.
- #perform(user) ⇒ Object
Instance Method Details
#mark_provisioning_failed(user, reason) ⇒ Object
Settles the row in failed — but only when this job holds the claim (row is in provisioning), so a stale job can never clobber a row another job has since taken to ready. Public because the retry_on exhaustion block runs outside the instance’s private context.
71 72 73 74 75 |
# File 'app/jobs/solrengine/sdp/provision_wallet_job.rb', line 71 def mark_provisioning_failed(user, reason) user.class .where(id: user.id, sdp_provisioning_state: "provisioning") .update_all(sdp_provisioning_state: "failed", sdp_provisioning_error: reason) end |
#perform(user) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'app/jobs/solrengine/sdp/provision_wallet_job.rb', line 48 def perform(user) return if user.wallet_ready? return unless claim(user) wallet = existing_wallet_for(user) || create_wallet_for(user) user.update!( sdp_wallet_id: wallet.id, wallet_address: wallet.public_key, sdp_provisioning_state: "ready", sdp_provisioning_error: nil ) rescue ::Sdp::Unavailable, ::Sdp::Timeout raise # retry_on handles backoff; the claim stays held for the retry rescue ::Sdp::Error => e # Terminal: capability gates (AE1) and auth/validation errors fail the # same way no matter how often they are retried. Reason is renderable. mark_provisioning_failed(user, e.) end |