Skip to content
jfarcand edited this page Feb 21, 2026 · 2 revisions

Durable Sessions

WebSocket sessions are ephemeral — when the server restarts, all connections are lost and clients must reconnect from scratch, losing their room memberships, broadcaster subscriptions, and application metadata. Durable Sessions solve this by persisting session state to a backing store (SQLite or Redis) so that reconnecting clients automatically resume exactly where they left off.

Architecture

┌──────────────┐     X-Atmosphere-Session-Token     ┌──────────────────────┐
│  atmosphere.js│ ──────────────────────────────────→ │ DurableSession       │
│  client       │ ←────────────────────────────────── │ Interceptor          │
└──────────────┘     token assigned on first connect │                      │
                                                      │  save / restore      │
                                                      └──────────┬───────────┘
                                                                 │
                                                      ┌──────────▼───────────┐
                                                      │    SessionStore SPI  │
                                                      ├──────────────────────┤
                                                      │ InMemorySessionStore │ (dev/test)
                                                      │ SqliteSessionStore   │ (single-node)
                                                      │ RedisSessionStore    │ (clustered)
                                                      └──────────────────────┘

Quick Start (Spring Boot)

1. Add Dependencies

<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-spring-boot-starter</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-durable-sessions</artifactId>
    <version>4.0.1</version>
</dependency>
<!-- Pick one: -->
<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-durable-sessions-sqlite</artifactId>
    <version>4.0.1</version>
</dependency>

2. Enable in Properties

atmosphere.durable-sessions.enabled=true
atmosphere.durable-sessions.session-ttl-minutes=1440
atmosphere.durable-sessions.cleanup-interval-seconds=60

3. Provide a SessionStore Bean

@Bean
public SessionStore sessionStore() {
    return new SqliteSessionStore(Path.of("data/sessions.db"));
}

If no SessionStore bean is defined, an InMemorySessionStore is used automatically (useful for development, but sessions won't survive restarts).

4. Client Side

import { atmosphere } from 'atmosphere.js';

const atmosphere = new Atmosphere();
const sub = await atmosphere.subscribe({
  url: '/atmosphere/chat',
  transport: 'websocket',
  sessionToken: localStorage.getItem('atmo-session-token'),
});

The sessionToken is sent as X-Atmosphere-Session-Token on every request.

SessionStore SPI

The SessionStore interface defines six methods:

Method Description
save(session) Persist a session (upsert)
restore(token) Look up a session by token
remove(token) Delete a session
touch(token) Update the last-seen timestamp
removeExpired(ttl) Find and remove sessions older than TTL
close() Release resources

DurableSession Record

public record DurableSession(
    String token,          // unique session token
    String resourceId,     // AtmosphereResource UUID
    Set<String> rooms,     // room names
    Set<String> broadcasters, // broadcaster IDs
    Map<String, String> metadata, // app-defined key-value pairs
    Instant createdAt,
    Instant lastSeen
) { }

Implementations

SQLite (Single-Node)

Zero-configuration, embedded database. Perfect for single-node deployments, development, and edge/IoT scenarios.

// Default: atmosphere-sessions.db in working directory
var store = new SqliteSessionStore();

// Custom path
var store = new SqliteSessionStore(Path.of("/data/sessions.db"));

// In-memory (for testing)
var store = SqliteSessionStore.inMemory();

Maven:

<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-durable-sessions-sqlite</artifactId>
    <version>4.0.1</version>
</dependency>

Redis (Clustered)

Sessions shared across all nodes via Redis. Ideal for multi-node production deployments and Kubernetes environments.

// Basic connection
var store = new RedisSessionStore("redis://localhost:6379");

// With custom TTL
var store = new RedisSessionStore("redis://localhost:6379", Duration.ofHours(12));

// Share connection with atmosphere-redis clustering
var store = new RedisSessionStore(existingLettuceConnection, Duration.ofHours(24));

Maven:

<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-durable-sessions-redis</artifactId>
    <version>4.0.1</version>
</dependency>

How It Works

  1. First connectionDurableSessionInterceptor.inspect() creates a new DurableSession with a UUID token, saves it to the store, and sends the token back via X-Atmosphere-Session-Token response header.

  2. Disconnect — A listener captures the client's current rooms and broadcaster subscriptions and saves them to the store.

  3. Reconnection — The client sends its token. The interceptor restores the session, re-subscribes to all broadcasters, and re-joins all rooms.

  4. Cleanup — A background virtual thread periodically removes sessions that haven't been seen within the configured TTL.

Programmatic Registration

If not using Spring Boot auto-configuration:

var store = new SqliteSessionStore();
var interceptor = new DurableSessionInterceptor(
    store,
    Duration.ofHours(24),    // session TTL
    Duration.ofMinutes(1)    // cleanup interval
);
framework.interceptor(interceptor);

Configuration Reference

Property Default Description
atmosphere.durable-sessions.enabled false Enable durable sessions
atmosphere.durable-sessions.session-ttl-minutes 1440 Session time-to-live in minutes (24h)
atmosphere.durable-sessions.cleanup-interval-seconds 60 Expired session cleanup interval

Clone this wiki locally