Class: Legate::SessionService::InMemory

Inherits:
Base
  • Object
show all
Includes:
EventBroadcast
Defined in:
lib/legate/session_service/in_memory.rb

Overview

Stores sessions entirely in memory. Data is lost on application restart. Useful for local development, testing, and simple use cases.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from EventBroadcast

#broadcast_event, #subscribe, #unsubscribe

Constructor Details

#initializeInMemory

Returns a new instance of InMemory.



19
20
21
22
23
# File 'lib/legate/session_service/in_memory.rb', line 19

def initialize
  @sessions = Concurrent::Map.new
  @scoped_states = Concurrent::Map.new
  Legate.logger.info('InMemorySessionService initialized.')
end

Instance Attribute Details

#scoped_statesObject (readonly)

Returns the value of attribute scoped_states.



17
18
19
# File 'lib/legate/session_service/in_memory.rb', line 17

def scoped_states
  @scoped_states
end

#sessionsObject (readonly)

Returns the value of attribute sessions.



17
18
19
# File 'lib/legate/session_service/in_memory.rb', line 17

def sessions
  @sessions
end

Instance Method Details

#append_event(session_id:, event:) ⇒ Boolean

— REVISED METHOD — Appends an event to a session and merges state updates from the event’s state_delta. This should be the primary way to modify a session during a turn.

Parameters:

  • session_id (String)

    The ID of the session to update.

  • event (Legate::Event)

    The event to append. Must be an instance of Legate::Event.

Returns:

  • (Boolean)

    True if successful, false if session not found or event is invalid.



93
94
95
96
97
98
99
100
# File 'lib/legate/session_service/in_memory.rb', line 93

def append_event(session_id:, event:)
  session = get_session(session_id: session_id)
  return false unless session

  session.add_event(event)
  broadcast_event(session_id, event) # notify any streaming subscribers (R3)
  true
end

#clear_scoped_state(scope, key) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
# File 'lib/legate/session_service/in_memory.rb', line 139

def clear_scoped_state(scope, key)
  if key == '*'
    # Clear all states for the given scope
    @scoped_states.keys.each do |state_key|
      @scoped_states.delete(state_key) if state_key.start_with?("#{scope}:")
    end
  else
    state_key = "#{scope}:#{key}"
    @scoped_states.delete(state_key)
  end
end

#create_session(app_name:, user_id:, session_id: nil, initial_state: {}) ⇒ Legate::Session

Creates a new session in memory.

Parameters:

  • app_name (String)

    Identifier for the agent application.

  • user_id (String)

    Identifier for the user initiating the session.

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

    Optional explicit session id (defaults to a generated UUID).

  • initial_state (Hash) (defaults to: {})

    Optional initial data for the session state.

Returns:



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/legate/session_service/in_memory.rb', line 35

def create_session(app_name:, user_id:, session_id: nil, initial_state: {})
  # Fix: Ensure keys are symbols before passing to Session constructor
  symbolized_state = initial_state.transform_keys { |k|
    begin
      k.to_sym
    rescue StandardError
      k
    end
  }
  session = Legate::Session.new(
    app_name: app_name,
    user_id: user_id,
    id: session_id,
    initial_state: symbolized_state,
    session_service: self
  )
  @sessions[session.id] = session
  Legate.logger.info("Created session: #{session.id} for app:#{app_name}, user:#{user_id}")
  session
end

#delete_session(session_id:) ⇒ Boolean

Deletes a session from memory.

Parameters:

  • session_id (String)

    The ID of the session to delete.

Returns:

  • (Boolean)

    True if a session was deleted, false otherwise.



105
106
107
108
109
110
111
112
113
114
# File 'lib/legate/session_service/in_memory.rb', line 105

def delete_session(session_id:)
  deleted_session = @sessions.delete(session_id)
  if deleted_session
    Legate.logger.info("Deleted session: #{session_id}")
    true
  else
    Legate.logger.warn("Attempted to delete non-existent session: #{session_id}")
    false
  end
end

#get_session(session_id:) ⇒ Legate::Session?

Retrieves a session from memory by its ID.

Parameters:

  • session_id (String)

    The unique ID of the session to retrieve.

Returns:



59
60
61
62
63
64
65
66
67
# File 'lib/legate/session_service/in_memory.rb', line 59

def get_session(session_id:)
  session = @sessions[session_id]
  if session
    Legate.logger.debug("Retrieved session: #{session_id}")
  else
    Legate.logger.warn("Session not found: #{session_id}")
  end
  session
end

#get_state(session_id:, key:) ⇒ Object?

Retrieves a value from the state associated with the session. Delegates to the Legate::Session instance’s get_state method.

Parameters:

  • session_id (String)

    The ID of the session.

  • key (Symbol)

    The key for the state entry.

Returns:

  • (Object, nil)

    The value if found, or nil.



177
178
179
180
181
182
183
184
185
# File 'lib/legate/session_service/in_memory.rb', line 177

def get_state(session_id:, key:)
  session = get_session(session_id: session_id)
  if session
    session.get_state(key) # Legate::Session#get_state handles its own logic
  else
    Legate.logger.warn("InMemorySessionService: Session not found '#{session_id}' when trying to get state for key '#{key}'.")
    nil
  end
end

#list_sessions(app_name: nil, user_id: nil) ⇒ Array<Legate::Session>

Lists sessions (in this implementation, just returns all session objects). Filtering could be added later if needed.

Parameters:

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

    Optional filter by app name.

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

    Optional filter by user ID.

Returns:

  • (Array<Legate::Session>)

    An array of session objects matching filters.



121
122
123
124
125
126
127
# File 'lib/legate/session_service/in_memory.rb', line 121

def list_sessions(app_name: nil, user_id: nil)
  filtered = @sessions.values # Get all session objects
  filtered.select! { |s| s.app_name == app_name } if app_name
  filtered.select! { |s| s.user_id == user_id } if user_id
  Legate.logger.debug("Listing #{filtered.count} sessions.")
  filtered
end

#load_scoped_state(scope, key) ⇒ Object



134
135
136
137
# File 'lib/legate/session_service/in_memory.rb', line 134

def load_scoped_state(scope, key)
  state_key = "#{scope}:#{key}"
  @scoped_states[state_key]
end

#persistent?Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/legate/session_service/in_memory.rb', line 25

def persistent?
  false
end

#save_scoped_state(scope, key, value) ⇒ Object



129
130
131
132
# File 'lib/legate/session_service/in_memory.rb', line 129

def save_scoped_state(scope, key, value)
  state_key = "#{scope}:#{key}"
  @scoped_states[state_key] = value
end

#save_session(session:) ⇒ Boolean

— DEPRECATED — Saves the session state (in memory this just means it’s already updated). In a persistent store, this would write changes. Here, we just update the timestamp. NOTE: Events and state updates should be done via #append_event for atomicity. This method mainly exists for interface compatibility if needed but should be avoided.

Parameters:

Returns:

  • (Boolean)

    True if the session exists in memory.



76
77
78
79
80
81
82
83
84
85
# File 'lib/legate/session_service/in_memory.rb', line 76

def save_session(session:)
  if @sessions.key?(session.id)
    session.updated_at = Time.now.utc # Ensure timestamp reflects save attempt
    Legate.logger.warn('InMemorySessionService#save_session called (likely unnecessary). Use append_event.')
    true
  else
    Legate.logger.error("Attempted to save non-existent session: #{session.id}")
    false
  end
end

#set_state(session_id:, key:, value:) ⇒ void

This method returns an undefined value.

Sets a key-value pair in the state associated with the session. Delegates to the Legate::Session instance’s set_state method.

Parameters:

  • session_id (String)

    The ID of the session.

  • key (Symbol)

    The key for the state entry.

  • value (Object)

    The value to store.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/legate/session_service/in_memory.rb', line 157

def set_state(session_id:, key:, value:)
  session = get_session(session_id: session_id)
  if session
    begin
      session.set_state(key, value) # Legate::Session#set_state handles its own logging
    rescue Legate::SerializationError => e # Catch potential serialization errors from session.set_state
      Legate.logger.error("InMemorySessionService: Error setting state for session '#{session_id}', key '#{key}': #{e.message}")
      # Depending on desired behavior, could re-raise or just log
    end
  else
    Legate.logger.warn("InMemorySessionService: Session not found '#{session_id}' when trying to set state for key '#{key}'.")
  end
  nil # Return void consistent with base
end