Class: SpreeCmCommissioner::AsyncOperation

Inherits:
Base
  • Object
show all
Includes:
StoreMetadata
Defined in:
app/models/spree_cm_commissioner/async_operation.rb

Overview

A long-running operation a human started and is waiting on the result of, with a status an admin screen can poll: queue -> progress -> done | failed.

SCOPE RULE: operations a person initiated and is watching. Not webhook deliveries, not per-order background work, not general job logging.

That rule is what keeps this table small enough to need no retention policy -- admin actions are rare, and the rows are a few hundred bytes of jsonb. cm_exports, the table this is modelled on, has grown unpruned while storing actual files. If a future subclass ever puts high-volume work here, add a purge alongside cleanup_integration_sync_sessions in config/schedule.yml; the [type, status, created_at] index exists to serve exactly that query.

Subclasses supply their own payload/result keys via store_*_metadata and implement #process!. See AsyncOperations::SeatLock.

Constant Summary collapse

ERROR_LIMIT =
1000

Instance Method Summary collapse

Instance Method Details

#enqueueObject

Subclasses may override to pick a different queue or a dedicated job.



35
36
37
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 35

def enqueue
  SpreeCmCommissioner::AsyncOperationJob.perform_later(async_operation_id: id)
end

#fail!(message) ⇒ Object

save(validate: false), not update!: this runs from a rescue block, so a subclass validation failing here would raise a second exception and bury the original. Recording a failure must not be able to fail.



64
65
66
67
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 64

def fail!(message)
  assign_attributes(status: :failed, finished_at: Time.current, error: message.to_s.truncate(ERROR_LIMIT))
  save(validate: false)
end

#finish!Object



57
58
59
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 57

def finish!
  update!(status: :done, finished_at: Time.current)
end

#in_progress?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 39

def in_progress?
  queue? || progress?
end

#process!Object

Raises:

  • (NotImplementedError)


69
70
71
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 69

def process!
  raise NotImplementedError, 'Subclasses must implement #process!'
end

#stale?Boolean

Heartbeat, not wall clock. A running operation touches the row as it accumulates results, so real work never looks stale while a killed worker does. Without this the admin panel spins forever.

Returns:

  • (Boolean)


45
46
47
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 45

def stale?
  in_progress? && updated_at < timeout.ago
end

#start!Object



53
54
55
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 53

def start!
  update!(status: :progress, started_at: Time.current)
end

#timeoutObject



49
50
51
# File 'app/models/spree_cm_commissioner/async_operation.rb', line 49

def timeout
  20.minutes
end