10BC0 Implement DDP session resumption for graceful reconnects by vlasky · Pull Request #14051 · meteor/meteor · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@vlasky
Copy link
Contributor
@vlasky vlasky commented Dec 12, 2025

Summary

This PR implements DDP session resumption, allowing clients to automatically resume their previous session after a temporary network disconnect without re-triggering onConnection callbacks or losing their connection ID.

This PR supersedes PR #13378 with a completely rewritten implementation that includes comprehensive tests to give everyone confidence in its correctness.

Key Features

  • Automatic session resumption: When a client reconnects within the grace period (default 15 seconds), their session is seamlessly restored
  • Configurable grace period: Meteor.server.options.disconnectGracePeriod (default: 15000ms)
  • Message queue limit: Meteor.server.options.maxMessageQueueLength (default: 100) prevents memory leaks during disconnects
  • Graceful vs ungraceful disconnect handling: Only ungraceful disconnects (network loss, browser close) allow resumption; graceful disconnects (explicit logout, server kick) do not
  • Message count verification: Server validates client's received message count to ensure no messages were lost

Implementation Details

Client-side changes (ddp-client):

  • Track receivedCount of messages from server (excluding ping/pong)
  • Send receivedCount in reconnect messages
  • Handle session_resumed vs new session responses
  • Send disconnect message before intentional disconnects

Server-side changes (ddp-server):

  • Maintain sentCount of messages sent to each client
  • On disconnect, queue session for removal after grace period
  • On reconnect with matching session ID and count, resume session
  • Prevent resumption for graceful disconnects and server-initiated closes
  • Guard against double cleanup and memory leaks

Comprehensive Test Coverage

Server-side tests (7 new tests):

  • DDP resumption: unexpected disconnect preserves session - verifies grace period works
  • DDP resumption: graceful disconnect removes session immediately - verifies client disconnect msg works
  • DDP resumption: server-initiated close removes session immediately - verifies server kicks work
  • DDP resumption: onConnection not called on resume - verifies hook behavior
  • DDP resumption: server close prevents resumption - verifies server kicks are not resumable
  • DDP resumption: graceful disconnect prevents resumption - verifies client disconnects are not resumable
  • DDP resumption: count mismatch creates new session - verifies mismatched counts create new session

Client-side tests (5 new tests):

  • receivedCount tracking - verifies count increments and ignores ping/pong
  • receivedCount sent on reconnect - verifies reconnect includes count
  • receivedCount reset on new session - verifies reset on new session
  • receivedCount preserved on session resume - verifies count continues on resume
  • disconnect sends disconnect message - verifies disconnect() sends msg

Documentation

Updated v3-docs to document the new feature and configuration options.

Test plan

  • All existing ddp-server tests pass
  • All existing ddp-client tests pass
  • New DDP resumption tests pass
  • Verified with automated Puppeteer testing (page reload simulation)

Closes #13378

vlasky and others added 2 commits December 12, 2025 12:35
This feature allows Meteor clients to resume their DDP connections after
temporary disconnections without re-establishing full session state.

Key changes:
- Server tracks sent message count per session (sentCount)
- Client tracks received message count (receivedCount)
- On reconnect, client sends receivedCount with session ID
- Server validates counts match to allow session resumption
- New disconnect message allows graceful disconnects
- Grace period (default 15s) keeps session alive after disconnect
- Message queue (max 100) buffers messages during disconnect

Server options:
- Meteor.server.options.disconnectGracePeriod (default: 15000ms)
- Meteor.server.options.maxMessageQueueLength (default: 100)

This significantly reduces server CPU spikes when clients reconnect
(e.g., after Google Cloud Run timeouts) by avoiding full session
recreation and data re-fetch.

Based on PR meteor#13378. Rebased onto current devel branch with refactored
ddp-client handlers.

Co-authored-by: Jan Dvorak <AsciiDoctor@outlook.com>
Co-authored-by: Valentin Slatineanu <valentin.slatineanu@gmail.com>
Co-authored-by: zodern <zodern@icloud.com>
The test was failing when the browser page was reloaded during test runs
because the subscription ready callback could fire before the added
messages arrived. This can happen when a previous test run was
interrupted and the server is still processing the old session.

The fix adds a polling mechanism to wait for data to arrive before
asserting, with a 5-second timeout.
@netlify
Copy link
netlify bot commented Dec 12, 2025

Deploy Preview for v3-meteor-api-docs ready!

Name Link
🔨 Latest commit d09220f
🔍 Latest deploy log https://app.netlify.com/projects/v3-meteor-api-docs/deploys/6968f055a1418e0007a1b8f1
😎 Deploy Preview https://deploy-preview-14051.docs-online.meteor.com
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
netlify bot commented Dec 12, 2025

Deploy Preview for v3-migration-docs canceled.

Name Link
🔨 Latest commit 2aa5782
🔍 Latest deploy log https://app.netlify.com/projects/v3-migration-docs/deploys/69681201c694310008536a32

Copy link
Contributor
Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements DDP session resumption, allowing clients to automatically reconnect to their previous session after temporary network disconnects without triggering onConnection callbacks or losing their connection ID. The implementation uses message count tracking to verify data consistency and supports graceful vs. ungraceful disconnect handling with a configurable grace period (default 15 seconds).

Key Changes:

  • Server tracks sent message count and queues messages during disconnects for later replay
  • Client tracks received message count and sends it during reconnect attempts
  • Sessions are preserved during a grace period for ungraceful disconnects, with automatic cleanup for graceful disconnects or timeouts

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
v3-docs/docs/api/meteor.md Documents the new session resumption feature and configuration options (disconnectGracePeriod, maxMessageQueueLength)
packages/ddp-server/livedata_server.js Implements server-side session resumption logic including message counting, session queueing, grace period handling, and disconnect type detection
packages/ddp-server/livedata_server_tests.js Adds comprehensive test suite (7 tests) covering grace period behavior, graceful vs ungraceful disconnects, onConnection hook behavior, and count mismatch scenarios
packages/ddp-server/livedata_server_async_tests.js Adds defensive polling to handle race conditions from lingering sessions in test environment
packages/ddp-client/common/livedata_connection.js Initializes receivedCount tracking and sends disconnect message before closing connection
packages/ddp-client/common/connection_stream_handlers.js Tracks received message count (excluding ping/pong) and includes it in reconnect messages
packages/ddp-client/common/message_processors.js Handles receivedCount reset for new sessions vs preservation for resumed sessions
packages/ddp-client/test/livedata_connection_tests.js Adds client-side tests (5 tests) for receivedCount tracking, session resume vs new session behavior, and disconnect message sending; updates existing tests to include receivedCount in connect messages
packages/ddp-client/test/stub_stream.js Adds disconnect() stub method for testing

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Fix wording: "insure" → "to help prevent" in docs and JSDoc
- Extract heartbeat cleanup to _stopHeartbeat() helper method
- Simplify disconnect handling: remove redundant condition check
- Update documentation: add Reconnection section, use "Meteor 3.5+"
  instead of time-sensitive language, update PR link to meteor#14051
- Update comment at line 1480 to reflect session resume/create behavior
- Replace delete statements with = undefined for V8 JIT optimization
- Remove unused variable clientConn in test
- Add comment clarifying _permanent flag purpose in close()
@vlasky vlasky requested a review from italojs December 23, 2025 06:07
@italojs italojs changed the base branch from devel to release-3.4.1 January 15, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0