Skip to content

Reconnect and Heartbeat ​

Problem ​

A realtime session must recover from network loss without opening duplicate sockets or replaying application messages before its channel and room state exists.

Solution ​

Enable reconnect and heartbeat, create scopes before connecting, and subscribe to the status external store.

ts
import { createPulse } from '@vielzeug/pulse';

type Schema = {
  channels: {
    chat: {
      client: { send: { text: string } };
      server: { message: { text: string } };
    };
  };
  rooms: {
    lobby: { presence: { name: string } };
  };
};

const pulse = createPulse<Schema>('wss://api.example.com/ws', {
  heartbeat: { interval: 20_000, timeout: 8_000 },
  reconnect: { delay: (attempt) => Math.min(500 * 2 ** attempt, 30_000), maxAttempts: 8 },
});
pulse.tap((event) => {
  if (event.type === 'error') console.error(event.error);
  if (event.type === 'status-change') console.log('status:', event.status);
});
const chat = pulse.channel('chat');
const lobby = pulse.room('lobby');

const stopStatus = pulse.status.subscribe(() => {
  console.log('Pulse status:', pulse.status.getSnapshot());
});

try {
  await pulse.connect();
  chat.on('message', ({ text }) => console.log(text));
  await lobby.joined;
  lobby.updatePresence({ name: 'Ada' });
} catch (error) {
  console.error('Pulse connection failed:', error);
} finally {
  stopStatus();
  lobby.dispose();
  chat.dispose();
  pulse.dispose();
}

Pitfalls ​

  • disconnect() cancels retry immediately. It never leaves a scheduled reconnect behind.
  • Restoration is ordered. Pulse resubscribes channels, rejoins rooms, then restores the last successfully published local presence state.
  • status is transport state. Wait for the server's own restored-room data before acting on room membership.