Class: SpreeCmCommissioner::WaitingRoom::AdvanceQueue

Inherits:
Object
  • Object
show all
Extended by:
ServiceModuleThrowable
Includes:
Spree::ServiceModule::Base, FirestoreConnection
Defined in:
app/services/spree_cm_commissioner/waiting_room/advance_queue.rb

Overview

Merges the three independently-scheduled crons (Heartbeat::Sweep, Positions::Stamp, Admission::CallGuests) into one execution, sharing one Firestore client instead of each opening its own.

Ordering is the design, not an implementation detail: Sweep runs first so a stale doc it resolves frees a position before Stamp ever reads it; Stamp runs before CallGuests so every doc CallGuests selects is guaranteed to already have a position (no more call-before-stamp race), and so frontier_position always reflects the last already-landed writes rather than guessing about a cohort this tick's CallGuests hasn't even claimed yet — see Admission::CallGuests's class comment for why that keeps frontier lag bounded to one tick.

Also owns the lobby doc and its logs sub-doc: every step returns its fields (lobby:/logs: in its result) rather than writing directly. logs: is accumulated and written once, at the end — telemetry isn't user-facing, so batching it costs nothing. lobby: is instead flushed incrementally, right after each step that has fields to publish: frontier_position (from Stamp) lands the moment Stamp finishes, not gated behind CallGuests's own several sequential Firestore round trips afterward — CallGuests's own capacity fields get a second, small merge write once it finishes. frontier_position is the one field the app polls to count down "N people ahead of you" in something close to real time, so it's the one write worth not batching: one extra Firestore write per tick is cheap next to visibly stalling that counter for however long CallGuests takes. Sweep never contributes lobby fields, so it never adds a write. Also resolves the published records_path once (one lobby-doc read) and passes it into CallGuests, rather than CallGuests reading the lobby doc itself.

Whatever succeeded gets flushed the moment it's known, even when a later step then fails — a CallGuests failure after Stamp already published never withholds frontier_position, since it already landed before CallGuests even ran.

Instance Method Summary collapse

Methods included from ServiceModuleThrowable

call!

Methods included from FirestoreConnection

#firestore, #firestore_available?, #service_account

Instance Method Details

#callObject



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'app/services/spree_cm_commissioner/waiting_room/advance_queue.rb', line 35

def call
  started_at = Time.zone.now
  logs_fields = {}

  sweep_result = SpreeCmCommissioner::WaitingRoom::Heartbeat::Sweep.call(firestore: firestore)
  return publish_and_fail(logs_fields, started_at, sweep_result) if sweep_result.failure?

  publish_lobby(sweep_result.value[:lobby])
  logs_fields.merge!({ sweep: sweep_result.value[:logs] })

  stamp_result = SpreeCmCommissioner::WaitingRoom::Positions::Stamp.call(firestore: firestore)
  return publish_and_fail(logs_fields, started_at, stamp_result) if stamp_result.failure?

  publish_lobby(stamp_result.value[:lobby])
  logs_fields.merge!({ stamp: stamp_result.value[:logs] })

  call_result = SpreeCmCommissioner::WaitingRoom::Admission::CallGuests.call(
    firestore: firestore,
    records_path: records_path
  )

  return publish_and_fail(logs_fields, started_at, call_result) if call_result.failure?

  publish_lobby(call_result.value[:lobby])
  publish_logs(started_at, logs_fields.merge!({ call_guests: call_result.value[:logs] }))

  success(
    swept: sweep_result.value[:swept],
    stamped: stamp_result.value[:stamped],
    called_count: call_result.value[:called_count]
  )
end