fix(realtime): limit subscriptions per connection by jackeddisciple · Pull Request #14440 · appwrite/appwrite · GitHub
Skip to content

fix(realtime): limit subscriptions per connection - #14440

Merged
HarshMN2345 merged 2 commits into
appwrite:fix-realtime-subscription-limitfrom
jackeddisciple:fix-realtime-subscription-limits
Oct 15, 2026
Merged

HarshMN2345 merged 2 commits into
appwrite:fix-realtime-subscription-limitfrom
jackeddisciple:fix-realtime-subscription-limits

Conversation

@jackeddisciple

Copy link
Copy Markdown

What does this PR do?

A single realtime connection could keep piling up subscriptions until the worker hit its 512 MB limit and crashed, taking every other client on that worker down with it. This puts a ceiling on what one connection can hold.

  1. A connection can have at most 100 subscriptions and 100 distinct channels. Both are configurable through _APP_LIMIT_REALTIME_SUBSCRIPTIONS and _APP_LIMIT_REALTIME_CHANNELS.
  2. A subscription's queries can be at most 4096 chars in total, the same number REST allows for one query string. Without this the bloat just moves into fat queries (100 subs with ~16k values each held ~67 MB).
  3. The subscription count is tracked on the connection now, so subscribe, unsubscribe, auth and close don't rebuild the whole metadata array just to count it. Removing one subscription also only walks that connection's roles and channels instead of the entire project tree.

Going over a limit rejects the whole batch before anything is applied and closes with 1008, same as the other subscribe policy violations. It applies to both the URL handshake and subscribe messages.

Test Plan

Added unit tests for the counting, resubscribe, unsubscribe and query length paths, and e2e tests for both limits on the URL and message paths plus the long query case. Unit tests, pint, phpstan and rector all pass locally. I couldn't run the e2e suite on my machine, so CI will be their first run.

I also replayed the attack from the issue against the real Subscribe handler (300 subs per frame on one shared channel). On main it reached 30k subscriptions holding 71.5 MB, and matching a single event took 100 ms. On this branch the very first frame gets rejected. Maxing out every limit at once (100 subs, 100 long channel names, ~1000 query values each) lands around 10 MB per connection.

Related PRs and Issues

Fixes #14430

Checklist

  • Have you read the Contributing Guidelines on issues?
  • If the PR includes a change to an API's metadata (desc, label, params, etc.), does it also include updated API specs and example docs?

One connection could keep adding subscriptions until the realtime worker ran out of memory and dropped every other client with it. Connections now stop at 100 subscriptions and 100 channels (both configurable), a subscription's queries can be at most 4096 chars, and the subscription count is tracked as we go instead of rebuilding the whole metadata array on every message.

Fixes appwrite#14430
@hansi-codes

hansi-codes Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Tier S · Looks good to merge. Summary

@HarshMN2345
HarshMN2345 changed the base branch from main to fix-realtime-subscription-limit October 15, 2026 07:24
@HarshMN2345
HarshMN2345 merged commit 42b5176 into appwrite:fix-realtime-subscription-limit Oct 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Bug Report: Unbounded realtime subscriptions per connection crash the realtime worker and disconnect all its clients

2 participants