Class: SpreeCmCommissioner::WaitingRoom::Sessions::Issue

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

Constant Summary collapse

SESSION_CREATION_LOCK_KEY =
'waiting_room_session_creation'.freeze
WAITING_ROOM_SESSION_MAX_DURATION_IN_SECOND =

Soft ceiling on how long a session may keep renewing before it competes for capacity again (see #max_expired_at_ceiling and #renew_active_session). 600s default; HOLD_DURATION (8 min) + PAYMENT_LOCK_MIN_DURATION extension can push a genuinely active checkout to ~13 min, so this is a soft cap — past it, the session self-expires and the next call falls back to the full?-gated path, rather than being evicted outright.

(ENV['WAITING_ROOM_SESSION_MAX_DURATION_IN_SECOND'] || 600).to_i
WAITING_ROOM_SESSION_EXPIRE_DURATION_IN_SECOND =

How long a session's token/expired_at is valid before it needs renewal. 3min default.

(ENV['WAITING_ROOM_SESSION_EXPIRE_DURATION_IN_SECOND'] || (60 * 3)).to_i
WAITING_ROOM_BYPASS_HEADROOM_MULTIPLIER =

A verified bypasser is admitted past the normal max, but only up to this bounded headroom (max * multiplier) — never without limit — so a burst of stuck-payment returns can't push the protected pages far past capacity. Default 1.1 (10% headroom); 1 gates bypassers at max. See #bypass_full?.

(ENV['WAITING_ROOM_BYPASS_HEADROOM_MULTIPLIER'] || 1.1).to_f
PERMITTED_DEVICE_ATTRIBUTES =

Device attributes the client may set on the session. device_id and device_fingerprint are real columns; the rest are virtual columns backed by public/private metadata (see WaitingRoomSession). Anything else the client sends is dropped so we never persist arbitrary payloads.

%w[
  device_id device_fingerprint
  os_name os_version device_model device_manufacturer device_type
  device_environment app_version app_build timezone network_type
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ServiceModuleThrowable

call!

Methods included from FirestoreConnection

#firestore, #firestore_available?, #service_account

Instance Attribute Details

#bypass_jwtObject (readonly)

Returns the value of attribute bypass_jwt.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def bypass_jwt
  @bypass_jwt
end

#bypass_order_tokenObject (readonly)

Returns the value of attribute bypass_order_token.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def bypass_order_token
  @bypass_order_token
end

#device_attributesObject (readonly)

Returns the value of attribute device_attributes.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def device_attributes
  @device_attributes
end

#page_pathObject (readonly)

Returns the value of attribute page_path.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def page_path
  @page_path
end

#remote_ipObject (readonly)

Returns the value of attribute remote_ip.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def remote_ip
  @remote_ip
end

#tenant_idObject (readonly)

Returns the value of attribute tenant_id.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def tenant_id
  @tenant_id
end

#userObject (readonly)

Returns the value of attribute user.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def user
  @user
end

#waiting_guest_firebase_doc_idObject (readonly)

Returns the value of attribute waiting_guest_firebase_doc_id.



11
12
13
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 11

def waiting_guest_firebase_doc_id
  @waiting_guest_firebase_doc_id
end

Instance Method Details

#call(waiting_guest_firebase_doc_id:, remote_ip:, page_path: nil, tenant_id: nil, device_attributes: nil, bypass_jwt: nil, bypass_order_token: nil, user: nil) ⇒ Object

Three ways in here:

Condition #1 — queued: Admission::CallGuests precreated the row when it called this guest, so they just find and renew that existing row (if necessary).

Condition #2 — the row exists but its max_expired_at ceiling has already passed. Reject outright rather than silently reviving it: the ceiling is a hard cap the server controls, not something a renewal retry should be able to extend (see WaitingRoomSession#past_ceiling?).

Condition #3 — bypassed the queue: lobby doc showed full: false / has_queue: false, so the app called createSession directly. The caller never touched this guest, no row exists yet, so they fall through to a normal create_new_session. A row that's lapsed (expired_at passed) but still under its own ceiling also lands here — the revival path in #create_new_session.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/services/spree_cm_commissioner/waiting_room/sessions/issue.rb', line 55

def call(waiting_guest_firebase_doc_id:, remote_ip:, page_path: nil, tenant_id: nil, # rubocop:disable Metrics/ParameterLists
         device_attributes: nil, bypass_jwt: nil, bypass_order_token: nil, user: nil
)
  @waiting_guest_firebase_doc_id = waiting_guest_firebase_doc_id
  @remote_ip = remote_ip
  @page_path = page_path
  @tenant_id = tenant_id
  @device_attributes = device_attributes
  @bypass_jwt = bypass_jwt
  @bypass_order_token = bypass_order_token
  @user = user

  return failure(nil, 'must_provide_waiting_guest_firebase_doc_id') if waiting_guest_firebase_doc_id.blank?
  return failure(nil, 'must_provide_remote_ip') if remote_ip.blank?

  existing = SpreeCmCommissioner::WaitingRoomSession.find_by(guest_identifier: waiting_guest_firebase_doc_id)

  if existing&.active?
    success(room_session: renew_active_session(existing))
  elsif existing&.past_ceiling?
    failure(nil, 'waiting_room_session_expired')
  else
    create_new_session
  end
end