Module: Lich::Common::SessionsSettings

Defined in:
documented/common/settings/sessions_settings.rb

Constant Summary collapse

FEATURE_FLAG =
:session_summary_store_and_reporting
HEARTBEAT_INTERVAL_SECONDS =
90
STALE_THRESHOLD_SECONDS =
360
IDLE_OVER_30M_SECONDS =
1800
ADAPTER_MUTEX =
Mutex.new

Class Method Summary collapse

Class Method Details

.adapterSessionDatabaseAdapter

Retrieves the session database adapter, initializing it if necessary.

Returns:



28
29
30
31
32
33
34
# File 'documented/common/settings/sessions_settings.rb', line 28

def self.adapter
  return @adapter if @adapter

  ADAPTER_MUTEX.synchronize do
    @adapter ||= SessionDatabaseAdapter.new(db: Lich.db)
  end
end

.enabled?Boolean

Checks if the session summary store and reporting feature is enabled.

Returns:

  • (Boolean)

    true if the feature is enabled, false otherwise



20
21
22
23
24
# File 'documented/common/settings/sessions_settings.rb', line 20

def self.enabled?
  return false unless defined?(Lich::Common::FeatureFlags)

  Lich::Common::FeatureFlags.enabled?(FEATURE_FLAG)
end

.heartbeat(pid:, state: nil, hidden: nil, session_name: nil, role: nil, frontend: nil, game_code: nil, last_utilization_at: nil) ⇒ void

This method returns an undefined value.

Updates the heartbeat for an existing session.

Parameters:

  • pid (Integer)

    the process ID of the session

  • state (String, nil) (defaults to: nil)

    the current state of the session

  • hidden (Boolean, nil) (defaults to: nil)

    whether the session is hidden

  • session_name (String, nil) (defaults to: nil)

    the name of the session

  • role (String, nil) (defaults to: nil)

    the role of the session

  • frontend (String, nil) (defaults to: nil)

    optional frontend identifier

  • game_code (String, nil) (defaults to: nil)

    optional game code

  • last_utilization_at (Integer, nil) (defaults to: nil)

    optional timestamp of last utilization



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'documented/common/settings/sessions_settings.rb', line 79

def self.heartbeat(pid:, state: nil, hidden: nil, session_name: nil, role: nil, frontend: nil, game_code: nil, last_utilization_at: nil)
  return unless enabled?

  now = Time.now.to_i
  session_name = session_name || adapter.find_session(pid: pid)&.fetch('session_name', nil)
  os_presence_state = os_presence(pid: pid, session_name: session_name, now: now)
  adapter.upsert_session(
    pid: pid,
    session_name: session_name,
    role: role,
    state: state,
    frontend: frontend,
    game_code: game_code,
    hidden: hidden.nil? ? nil : (hidden ? 1 : 0),
    last_heartbeat_at: now,
    os_seen_at: os_presence_state[:os_seen_at],
    os_seen: os_presence_state[:os_seen],
    os_name: os_presence_state[:os_name],
    last_utilization_at: last_utilization_at
  )
end

.register_session(pid:, session_name:, role:, state:, frontend: nil, game_code: nil, hidden: false, metadata_json: nil) ⇒ void

This method returns an undefined value.

Registers a new session with the given parameters.

Parameters:

  • pid (Integer)

    the process ID of the session

  • session_name (String)

    the name of the session

  • role (String)

    the role of the session

  • state (String)

    the current state of the session

  • frontend (String, nil) (defaults to: nil)

    optional frontend identifier

  • game_code (String, nil) (defaults to: nil)

    optional game code

  • hidden (Boolean) (defaults to: false)

    whether the session is hidden

  • metadata_json (String, nil) (defaults to: nil)

    optional metadata in JSON format



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'documented/common/settings/sessions_settings.rb', line 46

def self.register_session(pid:, session_name:, role:, state:, frontend: nil, game_code: nil, hidden: false, metadata_json: nil)
  return unless enabled?

  now = Time.now.to_i
  sweep_dead_sessions!(now: now)
  os_presence_state = os_presence(pid: pid, session_name: session_name, now: now)
  adapter.upsert_session(
    pid: pid,
    session_name: session_name,
    role: role,
    state: state,
    frontend: frontend,
    game_code: game_code,
    hidden: hidden ? 1 : 0,
    started_at: now,
    last_heartbeat_at: now,
    os_seen_at: os_presence_state[:os_seen_at],
    os_seen: os_presence_state[:os_seen],
    os_name: os_presence_state[:os_name],
    metadata_json: 
  )
end

.snapshotHash

Takes a snapshot of the current active sessions.

Examples:

Get the current session snapshot

Lich::Common::SessionsSettings.snapshot

Returns:

  • (Hash)

    a hash containing session statistics and details



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'documented/common/settings/sessions_settings.rb', line 121

def self.snapshot
  return disabled_snapshot unless enabled?

  rows = adapter.active_sessions
  now = Time.now.to_i
  sessions = rows.map do |row|
    inactive = row['state'] == 'exited'
    if inactive
      os_seen = row['os_seen']
      os_name = row['os_name']
    else
      # Reporting uses authoritative live OS presence, but does not
      # persist those observations back into storage.
      live_presence = os_presence(pid: row['pid'], session_name: row['session_name'], now: now)
      os_seen = live_presence[:os_seen]
      os_name = live_presence[:os_name]
    end
    heartbeat_is_stale = stale?(row['last_heartbeat_at'], now)
    stale = !inactive && (heartbeat_is_stale || os_seen.to_i == 0)
    marker = inactive ? 'inactive' : (stale ? 'stale' : 'active')
    {
      pid: row['pid'],
      session_name: row['session_name'],
      state: row['state'],
      hidden: row['hidden'].to_i == 1,
      role: row['role'],
      last_heartbeat_at: row['last_heartbeat_at'].to_i,
      heartbeat_age: heartbeat_age(row['last_heartbeat_at'], now),
      stale: stale,
      marker: marker,
      os_seen: os_seen.to_i == 1,
      os_name: os_name.nil? ? nil : (os_name.to_i == 1),
      last_utilization: format_last_utilization(row['last_utilization_at'], now)
    }
  end

  {
    source: 'SessionsSettings',
    total: sessions.length,
    idle_over_30m: sessions.count { |s| !s[:heartbeat_age].nil? && s[:heartbeat_age] > IDLE_OVER_30M_SECONDS },
    stale: sessions.count { |s| s[:stale] },
    running: sessions.count { |s| s[:state] == 'running' },
    sleeping: sessions.count { |s| s[:state] == 'sleeping' },
    hidden: sessions.count { |s| s[:hidden] },
    sessions: sessions
  }
rescue StandardError => e
  disabled_snapshot(error: e.message)
end

.unregister_session(pid:) ⇒ void

This method returns an undefined value.

Unregisters a session by marking it as exited.

Parameters:

  • pid (Integer)

    the process ID of the session



104
105
106
107
108
109
110
111
112
113
114
115
# File 'documented/common/settings/sessions_settings.rb', line 104

def self.unregister_session(pid:)
  return unless enabled?

  now = Time.now.to_i
  adapter.upsert_session(
    pid: pid,
    state: 'exited',
    os_seen_at: now,
    os_seen: 0,
    os_name: 0
  )
end