Interface SessionRepository

All Known Implementing Classes:
InMemorySessionRepository, JdbcSessionRepository

public interface SessionRepository
The store of sessions and their logs. Implementations are thread-safe. The log is append-only: nothing updates, moves or removes an event, and a compaction is recorded by appending (see appendEvents(java.lang.String, java.util.List<org.springframework.ai.session.SessionEvent>, long)).
Since:
2.1.0
Author:
Christian Tzolov
  • Method Details

    • save

      Session save(Session session)
      Persists session metadata (create or update). If the session already exists its event log and its original Session.createdAt() are preserved; the other metadata fields are replaced.
      Returns:
      the saved session
    • saveIfAbsent

      boolean saveIfAbsent(Session session)
      Inserts the session unless one with the same id exists, atomically: a primary-key-guarded INSERT, or a compare-and-set put. SessionService.create(org.springframework.ai.session.CreateSessionRequest) relies on it, so two concurrent creates of one id cannot both succeed.
      Returns:
      true if the session was inserted, false if one with the same id exists; the existing session is left untouched
    • findById

      @Nullable Session findById(String sessionId)
    • findByMetadata

      List<Session> findByMetadata(String name, String value)
      The sessions whose metadata holds value under name, oldest first (creation time, then id). The one scoped lookup of the store, in the shape of Spring Session's findByIndexNameAndIndexValue: the store indexes attributes and has no notion of ownership. Every store indexes SessionAttributes.PRINCIPAL_NAME; a store that cannot index every key documents which others it answers for.
      Parameters:
      name - the metadata key
      value - the value, compared as a string
    • delete

      void delete(String sessionId)
      Deletes the session and its events.
    • deleteExpiredSessions

      int deleteExpiredSessions(Instant before)
      Deletes every session that expired before the given instant, with their events, in one atomic step per session, so a session whose expiry was extended concurrently (save(org.springframework.ai.session.Session)) is kept.
      Parameters:
      before - the expiry cut-off
      Returns:
      the number of sessions deleted
    • appendEvent

      void appendEvent(SessionEvent event)
      Appends one event to the log of the session named by SessionEvent.getSessionId().

      Idempotent by id: an event whose id is already in the session's log is a retried append and a no-op, neither a duplicate nor an error, and the version is not advanced. A caller that wants to retry safely supplies its own id rather than the builder's random one. Event ids are unique across sessions: a persistent store keys events by id alone and rejects an id used by another session rather than dropping the event.

      Throws:
      IllegalArgumentException - if the session does not exist
      IllegalStateException - if the id is used by an event of another session
    • appendEvents

      boolean appendEvents(String sessionId, List<SessionEvent> events, long expectedVersion)
      Appends several events in order, atomically, only if the log's version equals expectedVersion; otherwise nothing is written and false is returned. On success the version advances once, whatever the number of events. This is how a compaction is recorded: one EventType.COMPACTION boundary and its summary events, with the version check keeping two concurrent compactions from both landing. Read getEventVersion(java.lang.String) before findEvents(java.lang.String, org.springframework.ai.session.EventFilter), then pass that version here.
      Parameters:
      sessionId - the session whose log is appended to; every event must belong to it
      events - the events, in order; at least one, with ids that are new to the log
      expectedVersion - the version the caller read
      Returns:
      true when the events were appended, false when the version did not match
      Throws:
      IllegalArgumentException - if the session does not exist, the batch is empty, an event belongs to another session, or an id is already in the log or appears twice
    • getEventVersion

      long getEventVersion(String sessionId)
      The version of the session's log, advanced on every appendEvent(org.springframework.ai.session.SessionEvent) that appends a new event and on every successful appendEvents(java.lang.String, java.util.List<org.springframework.ai.session.SessionEvent>, long); 0 for a session that does not exist or has no events. Read it before findEvents(java.lang.String, org.springframework.ai.session.EventFilter), so that the version passed to appendEvents(java.lang.String, java.util.List<org.springframework.ai.session.SessionEvent>, long) is not newer than the events read.
    • findEvents

      List<SessionEvent> findEvents(String sessionId, EventFilter filter)
      The events of the session the filter selects, oldest first; an empty list for a session that does not exist.

      A EventFilter.Window.Last window returns the newest N matching events, extended back to the start of the turn it lands in (the nearest preceding turn start among the matches), so a tool call is never returned without its results; the extension is skipped when no turn start precedes the window. With EventFilter.activeView() the filter applies to the active view, the events the newest EventType.COMPACTION boundary names and everything appended after it, rather than to the whole log.

      EventFilter.apply(List) is the reference implementation of both. A store pushes the criteria and the window down to its query, so that a read does not cost the whole log, and may fetch only the rows a view can contain and hand them to apply, as JdbcSessionRepository does.