Class: SpreeCmCommissioner::WaitingRoom::StampQueuePositionsJob

Inherits:
ApplicationJob show all
Defined in:
app/jobs/spree_cm_commissioner/waiting_room/stamp_queue_positions_job.rb

Constant Summary collapse

STAMP_LIMIT =
(ENV['WAITING_ROOM_POSITION_STAMP_LIMIT'] || 1000).to_i
FIRESTORE_BATCH_SIZE =

Firestore bounds a batch update by payload size (10 MiB); this batch size leaves 500/commit far under that.

(ENV['WAITING_ROOM_FIRESTORE_BATCH_SIZE'] || 500).to_i

Instance Method Summary collapse

Methods included from ApplicationJobDecorator

handle_deserialization_error, prepended

Instance Method Details

#performObject



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
# File 'app/jobs/spree_cm_commissioner/waiting_room/stamp_queue_positions_job.rb', line 13

def perform
  paths = stamp_paths
  avg_queue_to_enter = lobby_data[:avg_queue_to_enter_seconds].to_i
  total = paths.sum { |p| waiting_count(p) }
  return if total.zero?

  stamped_at = Time.zone.now
  global = 0

  paths.each do |path|
    remaining = STAMP_LIMIT - global
    break if remaining <= 0

    docs = waiting_query(path).order('queued_at').limit(remaining).get.to_a

    # Stamp the docs in chunks: each_slice splits them into groups of at most
    # FIRESTORE_BATCH_SIZE, and each group is written in one firestore.batch commit
    # (so e.g. 1000 docs = 2 commits, not 1000 round-trips).
    docs.each_slice(FIRESTORE_BATCH_SIZE) do |slice|
      firestore.batch do |b|
        slice.each do |doc|
          global += 1

          # The app shows a progress bar via (queue_total - position + 1) / queue_total.
          # `position` only ever counts down toward 1, so we keep `queue_total` from ever
          # going down either (max of its old value and the current position) — it becomes
          # the guest's starting depth. That keeps the bar moving only forward, reaching
          # 100% at position 1, instead of jumping as the live waiting count shrinks.
          #
          # Example — a guest who started 8th, with the line draining from 8 to 4 people:
          #   live total:  position 6 / total 8 = 38%, then position 4 / total 4 = 25% (drops!) ❌
          #   this fix:    position 6 / total 8 = 38%, then position 4 / total 8 = 63% (climbs) ✅
          #                ...continuing to position 1 / total 8 = 100% at the front.
          data = {
            position: global,
            queue_total: [doc.data[:queue_total].to_i, global].max,
            estimated_wait_seconds: avg_queue_to_enter,
            status_updated_at: stamped_at
          }

          data[:position_set_at] = stamped_at unless doc.data[:position_set_at]
          b.update(doc.ref, data)
        end
      end
    end
  end
end