Repository navigation
Releases
v6.10.2
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- Ed25519 public key for EdDSA tokens. New option
client.token.ed25519_public_key(and the same option inclient.subscription_token) takes a PEM encoded Ed25519 public key to verify EdDSA signed connection and subscription tokens. Before, EdDSA tokens could be verified only with keys from a JWKS endpoint, while RSA and ECDSA keys could already be set directly. See JWT authentication (#1288). - JWKS key rotation and outages no longer disconnect clients for good (#1289). See JSON Web Key support:
- a token whose key is not returned by the JWKS endpoint (for example, during a key rollout, or a token signed with a retired key) is now treated as an expired token (
109, or3005on unidirectional transports), so the client gets a new token and reconnects. Before, it was an invalid token (3500), and client SDKs stopped reconnecting; - if the JWKS endpoint can't be reached, the client gets a temporary error and retries, instead of an invalid token;
- keys loaded from the JWKS endpoint are now kept for 5 minutes instead of one hour, so a key removed from the endpoint (for example, after a leak) stops working within 5 minutes. Keys already loaded are still used while the endpoint can't be reached;
- the same applies to subscription tokens. Tokens with a bad signature or malformed tokens are still invalid.
- a token whose key is not returned by the JWKS endpoint (for example, during a key rollout, or a token signed with a retired key) is now treated as an expired token (
proxy.protonow documents every message and field: what each request field carries, what each result field changes, and which responses honourerroranddisconnect. See also proxy docs (#1287).
Fixes
- Node metrics interval in the
infoserver API is the configured interval again (e.g.60), not a slightly different measured value like59.999856375(centrifugal/centrifuge#671).
Miscellaneous
- Docker image is rebuilt with the latest Alpine
ca-certificates-bundle, which removes trust in the compromised eMudhra intermediate CA certificates. Centrifugo itself already rejected these certificates since v6.10.1 (Go 1.27.3), but other tools in the image which use the system trust store did not, and container scanners reported the image as vulnerable (#1290). - This release is built with Go 1.27.3.
- Dependency updates.
- See also the corresponding Centrifugo PRO release.
v6.10.1
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
This release was created to upgrade to Go 1.27.3 which addresses golang/go#82345
Miscellaneous
- This release is built with Go 1.27.3.
- Dependency updates.
- See also the corresponding Centrifugo PRO release.
v6.10.0
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- Stricter JSON parsing in the client protocol. Centrifugo now follows RFC 8259 exactly. It rejects invalid UTF-8, repeated keys, extra data after a message, keys with different letter case and too large integers. Before, such messages were partly accepted. Now Centrifugo and your backend always read a message the same way, and invalid UTF-8 can't reach browsers (a browser closes the WebSocket when it gets invalid UTF-8). Official SDKs are not affected. See two edge cases in the behaviour changes below (centrifugal/protocol#56, centrifugal/centrifuge#652, #1259).
- Centrifugo now uses its own JSON code generator,
cfjson, instead ofeasyjson(andsegmentio/encodingfor decoding), and its own Protobuf generator,cfprotobuf, instead ofvtprotobuf. JSON output is the same byte for byte. In protocol benchmarks on Linux amd64, JSON encoding takes 46% less time and JSON decoding 25% less time (centrifugal/protocol#56). - Server API errors show if a retry makes sense. Errors have a new
temporaryfield (similar to the client protocol Error field): it istruewhen the same request may succeed later. There is a new error111 too many requests(HTTP 429, gRPCResourceExhausted). Requests which can never succeed now return 107 (bad request), 102 (unknown channel) or 108 (not available) instead of100 internal, so clients don't retry them (#1247). - Faster memory broker history. History is split into 64 parts by channel, each with its own lock. Before, all channels used one lock. Publishing with history into 10000 channels from all CPUs now takes 1.61Β΅s per publication instead of 2.90Β΅s (β44%) (centrifugal/centrifuge#666).
- Faster broadcast to subscriptions with positioning: Centrifugo reads the current time once per broadcast, not once per subscriber. 10β15% faster for 100 and 1000 subscribers (centrifugal/centrifuge#665).
- Unidirectional SSE no longer copies every message when writing it to a connection. With a 1 KB payload, memory allocated per delivered message dropped from about 1,220 bytes to 58 bytes, and with a 10 KB payload from about 10,650 bytes to 330 bytes. Garbage collection almost stops in these tests, and CPU usage is a few percent lower. Unidirectional HTTP streaming also allocates a bit less per message. Thanks @darakanoit (#1251).
- Broadcast with
publication_data_formatjsonorjson_objectchecks the data once per broadcast, not once per channel. A broadcast into 1000 channels with a 10 KB payload uses 60% less CPU (7.35 ms β 2.94 ms) and is 33% faster; with a 1 KB payload it uses 17% less CPU. Thanks @darakanoit (#1252). - Faster JWKS token verification under load. A JWKS cache hit no longer takes a lock or allocates memory. Parallel connect token verification is 34% faster with RSA-2048 keys (4.76 Β΅s β 3.13 Β΅s) and 15% faster with ES256 keys. Thanks @darakanoit (#1253).
- PostgreSQL stream and map brokers no longer allocate memory on an empty outbox poll. On an idle server, the stream broker allocated 25.8 MiB per second and the map broker 11.6 MiB per second; now both allocate about 130 KiB per second, with no garbage collection cycles. Thanks @darakanoit (#1250).
- Config reload on SIGHUP improvements. Before, if a subscription token setting failed to apply, the connection token settings were already changed, and Centrifugo worked with a mix of old and new settings (#1267).
- Redis IAM authentication (experimental). Centrifugo can connect to managed Redis/Valkey with short-lived cloud tokens instead of a static password:
aws_iam_authfor Amazon ElastiCache (node-based and Serverless),gcp_iam_authfor Google Cloud Memorystore andazure_entra_authfor Azure Managed Redis and Azure Cache for Redis. Credentials come from the cloud default chain (AWS SDK credentials, Google Application Default Credentials,DefaultAzureCredential), tokens are refreshed automatically. The options work everywhere Redis is configured: engine, broker, presence manager, map broker, Redis stream consumer. See Redis IAM authentication (#1118, #1283, centrifugal/centrifuge#670). - JWKS keys are updated after key rotation. Centrifugo loads keys from the JWKS endpoint again one hour after the last load. A key removed from the endpoint stops working within one hour. Before, a key which was used all the time was never loaded again. Also, tokens with unknown
kidvalues now share one request to the JWKS endpoint, so fake tokens can't overload it (#1255, #1264).
Behaviour changes
Most setups need no changes. Please check this list before upgrading:
- Publication data for JSON subscribers must be valid UTF-8 JSON. If you publish invalid UTF-8, or binary data (gRPC
dataor HTTPb64data) into a channel with JSON subscribers, they are disconnected with code3506(centrifugal/centrifuge#652). - Async consumers retry only temporary errors (100 and 111). For other errors, Centrifugo logs the error and marks the message as processed (#1247).
- Client publish into a namespace with a non-stream subscription type (
map,map_clients,map_users,shared_poll) is now refused with103 permission denied(#1280). - Join/leave override in a subscription token now works. If the token sets
join_leave: trueand the namespace hasjoin_leaveoff, the client gets join/leave messages when it asks for them and has presence permission. Before, Centrifugo checked only the namespace option (#1277). - Nats raw mode: if a channel has
publication_data_formatset tojsonorjson_object, messages which don't match it are not delivered (#1258). - A connection token with invalid
b64infois now an invalid token. The client is disconnected. Before, it reconnected again and again with the same token. An invalidpatternin thechannelsserver API call now returns 107 (bad request) instead of 100 (internal error) (#1267).
Fixes
- Join/leave, positioning and recovery requested by a client now work for subscriptions allowed by the subscribe proxy. Join/leave also works for subscribe stream proxy subscriptions. Permission checks are the same as for other subscriptions. Thanks @AdzerKI (#1270, #1277).
- A connection without user ID could subscribe to a user-limited channel with an empty user in it, such as
user#oruser#42,. Now it can't. Channels requested on connect are no longer subscribed in a namespace with subscribe stream proxy or with a non-stream subscription type (#1279, #1280). - Subscribe stream proxy fixes (#1262, #1272):
- closing the stream of an old subscription no longer unsubscribes a new one;
- a refused stream subscription no longer keeps a goroutine until disconnect;
- a first message which comes at the same moment as the timeout no longer leaves the subscription on a closed stream.
- With
client.concurrency, disconnect no longer waits for a timeout if the client goes away while its subscribe waits in the queue (#1268). - A
nullitem in a shared poll refresh proxy response, ornullchannel options in connect proxysubs, no longer crash Centrifugo (#1265, [centrifugal/centrifuge#647](https://github...
v6.9.7
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- Publications into a channel are no longer delayed by clients subscribing to it with recovery or positioning (see also the fix below). In a benchmark which publishes into a channel with 100 subscribers while other clients connect with it and a second channel whose history read takes 1ms, publish latency dropped from 249Β΅s to 28Β΅s on average and from 1240Β΅s to 46Β΅s at p99. Broadcasting to a client which is not subscribing to anything now costs an atomic load instead of a mutex and a map lookup (a broadcast to 100 subscribers went from 27.4Β΅s to 23.9Β΅s).
- Faster fossil delta encoding β Centrifugo now uses centrifugal/fdelta package instead of
shadowspore/fossil-delta. Creating a delta is 3.5-4.2x faster on JSON payloads and allocates once instead of five times (128 B/op at 16 KiB against 19 KB). centrifugal/centrifuge#638. - Less memory per connection. Client command handlers copied the whole configuration (about 10 KB) onto the stack of the connection's goroutine, so the stack grew on the first commands. They now read it by reference. With 20k connections which connect and subscribe, stack memory is 35% lower and process RSS about 20% lower β about 10 KB less per connection (#1244).
- Faster channel options lookup. Options are now resolved for every namespace once β on start and on every config reload β so a lookup is a map read without allocation. Before, Centrifugo cached the options of 1024 channels, and with more channels in use (a broadcast into thousands of channels, many personal channels) lookups kept missing the cache and allocated a copy of the options each time. A broadcast into 1000 channels is 27% faster and allocates about half the memory (#1245).
- Less work per broadcast when delta compression is used by JSON clients. A JSON client receives a delta as a JSON string, so a delta may only be built when the previous payload is valid UTF-8. Now a payload is scanned at most once per broadcast, and not at all when no JSON client takes deltas. It only matters for payloads carrying non-ASCII text (
utf8.Validhas an ASCII fast path) β on such payloads the broadcast is 12-21% faster depending on the number of encoding combinations in the channel (centrifugal/centrifuge#637).
Fixes
- Fix a possible node deadlock when a client subscribes to a channel with recovery or positioning enabled. Such a subscription kept its recovery buffer locked until the subscribe result was written, while a publication into the channel waited for that buffer holding the hub shard lock β so publications, subscribes, unsubscribes, disconnects and graceful shutdown for all channels of that shard could block. Publications no longer wait for a subscribing client (centrifugal/centrifuge#640). Reported in GHSA-xcch-wm46-g65g by @EJ-Research
- Delta compression and publication tags filters are documented as mutually exclusive, but Centrifugo still negotiated delta for a subscription with a tags filter. To keep the chain of deltas intact, publications filtered out for such a subscriber were sent to it anyway β so the filter was not applied at all. Delta is no longer negotiated for subscriptions with a tags filter (centrifugal/centrifuge#634).
- Map channels: when a channel's stream expired while its top offset and epoch survived, a read since an older offset returned an empty result with no error β recovery reported
recovered: truewhile silently skipping the lost publications. Such a read now results in an unrecoverable position error, so clients resync from the full state (centrifugal/centrifuge#636). - Publications buffered while a client subscribes with recovery or positioning are now limited by
client.queue_max_sizeper connection. Before, each subscription got the whole limit for itself, so a client subscribing to many channels at once β for example with server-side subscriptions on connect β could hold many times that limit in memory (centrifugal/centrifuge#641). - Redis Cluster: a channel whose name starts with
}made the keys of that channel land in different slots, which could crash the node β for example when a client subscribed to such a channel with recovery. Such channels are now refused with a bad request error (centrifugal/centrifuge#645). - The
unsubscribeserver API method now returns a bad request error whenchannelis empty, as documented. Before, it unsubscribed nothing but still sent the targeted connections an unsubscribe push for an empty channel (#1238).
Miscellaneous
- This release is built with Go 1.26.8.
- Dependency updates.
- See also the corresponding Centrifugo PRO release.
v6.9.6
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Fixes
- A client-side subscription refresh with an already expired subscription token was accepted. The subscription's expiration time was then cleared, so the subscription never expired. Now Centrifugo closes the connection with the
3006(subscription expired) disconnect code. The client reconnects, gets a token expired error on resubscribe and requests a new token β all official SDKs already handle this (centrifugal/centrifuge#627). - Fossil delta compression with recovery: when a subscribe with recovery found no missed publications, the next publication was still sent as a delta. The client had no base data for it, so it could not decode that publication or any after it. Now the first publication after such a subscribe is sent with full data (centrifugal/centrifuge#629).
- Align fossil deltas to UTF-8 character boundaries for JSON clients centrifugal/centrifuge#630. For a change inside a multi-byte character it copies the first bytes of the character from the previous data and inserts the rest. The inserted bytes aren't valid UTF-8, json.Escape replaces them with U+FFFD, and the client fails to apply the delta. The fix eliminates this.
Miscellaneous
- This release is built with Go 1.26.8.
- Dependency updates.
- See also the corresponding Centrifugo PRO release.
v6.9.5
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- Slightly less work when recording
centrifugo_client_ping_pong_duration_secondsβ the histogram observer is now cached instead of being looked up on every pong.
Fixes
- Fix possible panic in the channel options cache on long-running nodes. Its internal counter overflowed
int32after enough cache misses, which gave a negative slot index and crashed the node withindex out of range(#1227). - Map subscriptions: the subscribe reply did not include
expires/ttl, so clients could not refresh the subscription token in time. Also, if the map state was loaded in several pages, the client's subscription refresh was rejected with abad requestdisconnect. A subscription whose expiration time was already in the past was accepted (centrifugal/centrifuge#626). allowed_originspatterns with upper-case letters (e.g.https://App.Example.com) never matched, because the requestOriginwas lower-cased before matching and the pattern was not. Patterns are now matched case-insensitively (#1230).client_namewas ignored for Redis used byredis_streamasync consumers (#1229).- PostgreSQL engine: handle one more case of several nodes creating the schema at the same time β a node could fail on start with
type ... already exists(SQLSTATE42710) (#1231). - The
centrifugo_client_subscriptions_acceptedmetric was registered but never incremented, so it always showed zero (centrifugal/centrifuge#622). - The
client closed or unsubscribed after adding subscriptionmessage is now logged atinfolevel instead oferror. It happens when a client goes away while its subscription is still being set up β this is expected and is not a server error (centrifugal/centrifuge#621).
Miscellaneous
- Weβve updated the official Centrifugo dashboard. It covers all exposed metrics in v6.9.4, avoids deprecated Prometheus summaries, and includes descriptions for all panels. You can download it from grafana.com. See also Centrifugo's observability docs
- This release is built with Go 1.26.8.
- Dependency updates.
- See also the corresponding Centrifugo PRO release.
v6.9.4
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- New
centrifugo_transport_frame_sizemetric β a histogram of frame sizes received from client connections. One frame may contain several commands, so this can't be calculated from the existing per-command counters. Helps to choose a good value forwebsocket.message_size_limit, which is applied to the whole frame (centrifugal/centrifuge#620). - Faster Protobuf client protocol command encoding: ~2.1x faster and ~55% less memory alloc
- Less work on every client command: config accessors and the channel options cache no longer copy structs on each call (#1215).
- PostgreSQL broker, map broker and controller now validate
table_prefixon start. A prefix with a hyphen, space or dot used to produce a confusing syntax error inside a generatedCREATEstatement (#1223).
Fixes
- Async consumers: a
context.Cancelederror returned by the message dispatcher was treated as a shutdown signal. In the Kafka consumer this could skip records and then commit an offset after them, losing messages. This did not happen right now in Centrifugo, but inaccurately introduced code could cause this in the future. Fixed for Kafka and SQS (#1221). - fix(pgoutbox): tolerate 42P07 when another node creates the partition first #1220. Thanks to @AlexeyShalaev for bringing and fixing this.
- PostgreSQL engine: handle the case when several nodes create the schema at the same time. Before that a node which lost the race could fail to start with
error initializing Postgres ... schema. - PostgreSQL map broker: the fast path in
EnsureSchemanever worked, so every node start ran the full DDL batch again. It works now and also refreshes the partition lookahead (#1223). - Fix a race in log throttling of the connection limit check β it could print many duplicate warnings instead of one per throttle interval (#1214).
- Some config validation errors mentioned keys which don't exist, so it was hard to find the option to fix (#1213).
- Admin web UI: fix uptime formatting on the Status page (centrifugal/web#71).
Miscellaneous
- This release is built with Go 1.26.8.
- Dependency updates.
- See also the corresponding Centrifugo PRO release.
New Contributors
- @AlexeyShalaev made their first contribution in #1220
Full Changelog: v6.9.3...v6.9.4
v6.9.3
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- Faster and less allocating decoding of client commands. The command decoders are on the hot path β one is taken from the pool for every frame a client sends. The JSON decoder now reuses its buffered reader instead of allocating a new 4KB buffer per frame, and returns commands without allocating a slice per command when they fit into the read buffer. The Protobuf decoder unmarshals small messages straight out of the buffered reader instead of copying them into a scratch buffer first. Decoding a frame with a single JSON command got 62% faster with 93% less memory allocated, a frame with 8 commands β 25% faster with 67% less memory; for Protobuf the win is around 7-10% in time (centrifugal/protocol#41).
- The message size limit is now applied to every command in a JSON frame. Previously it was only checked reliably for the first command, so subsequent commands in the same frame could exceed the configured limit (up to roughly twice it). A command of exactly the limit is still accepted wherever it sits in the frame (centrifugal/protocol#41).
Fixes
- Fix
client.connection_rate_limit: the configured value was used as the token bucket burst only, while the sustained rate was one connection per second. Centrifugo now accepts the configured number of new connections per second, keeping the configured value as the burst size too. Thanks to @moses-mbaga for the fix (#1207). - Shared poll:
hmac_previous_secret_key_valid_untilwas compared against theiatclaim carried inside the track signature. That value is chosen by whoever mints the signature, so anyone retaining the rotated-out key could keep producing accepted signatures indefinitely by backdatingiat. The cutoff is now enforced against server time before consulting the previous verifier β the same way it works for the previous JWT HMAC key β with theiatcheck kept as an additional constraint inside the grace period (#1209). - Apply
publication_data_formaton all publication paths. It was only enforced for stream publishes (API publish, API broadcast, client publish), so map publish, shared poll publish and client map publish stored whatever bytes the caller sent. Data returned by publish, map publish and shared poll refresh proxies is now validated as well β a proxy can replace the data a client sent, and a shared poll refresh result reaches subscribers without ever passing through a client (#1210).
Miscellaneous
- This release is built with Go 1.26.7.
- Dependency updates.
- See also the corresponding Centrifugo PRO release.
New Contributors
- @moses-mbaga made their first contribution in #1207
Full Changelog: v6.9.2...v6.9.3
v6.9.2
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- Connection runtime stability, consistency, and performance improvements coming from the underlying Centrifuge library. Under connection churn and concurrent subscribe/unsubscribe on the same channel, Centrifugo now keeps its internal subscription state consistent, fixes several resource and presence leaks, and avoids possible metric drift. The periodic presence updates also use noticeably less CPU and memory. As part of this work some internal operations became up to 500x faster under certain conditions (centrifugal/centrifuge#590).
- Less memory allocation and garbage collection pressure on the message broadcast path. This mostly helps nodes that deliver many messages per second (centrifugal/centrifuge#598).
- Kafka consumer: copy fetched records into a compact slice before putting them into the internal partition queue. Previously the queued records could keep the whole underlying fetch buffer in memory, so memory usage grew more than expected when a consumer was lagging behind (#1195).
- Redis: read commands now fail within the expected time when Redis is unreachable, instead of silently retrying until Redis comes back. This makes behavior during a Redis outage predictable and matches how writes already worked (#1191 and centrifugal/centrifuge#591).
- Redis: bound the worst-case time to detect a silently stalled connection (the peer stops replying but the TCP connection stays open) to under 5 seconds by tuning the keepalive (#1192 and centrifugal/centrifuge#592).
- Redis: verify PUB/SUB delivery with liveness probes to detect a broken subscription connection earlier (centrifugal/centrifuge#594).
- Add per-IP throttling of failed attempts on the admin password login endpoint (
POST /admin/auth) to slow down brute-force. A valid login is not affected, even while an attack is in progress. This is best-effort protection only β the admin endpoint should still be protected at the infrastructure level (firewall rules, private network, authenticating reverse proxy) (#1204). - Harden the binary (Protobuf) protocol frame decoder so that a crafted length prefix can no longer make the server allocate too much memory. The configured message size limit is now always applied when reading client commands (#1203 and centrifugal/centrifuge#612).
- Redis Sentinel: the Sentinel client now periodically refreshes its topology, so changes such as a new master after a failover are picked up more reliably (#1201 and centrifugal/centrifuge#611).
- Redis Sentinel: Centrifugo also inherited several important Redis Sentinel setup stability improvements from the updated
rueidisclient (v1.0.77 release notes).
Fixes
- Fix a possible server process crash (nil pointer panic) that could happen when a delta publication failed to encode to JSON. The broadcast goroutine could panic and terminate the whole node (centrifugal/centrifuge#597).
- Fix a case where a client could end up with several concurrent connections on the server under Redis load. On disconnect the transport is now closed before the per-channel cleanup, so a slow Redis no longer delays the socket teardown of the old connection (centrifugal/centrifuge#595).
- Async consumers: do not acknowledge messages that were still being consumed during shutdown, so such messages are re-delivered later instead of being lost (#1196).
- Logging: raise the internal log handler buffer from 64 to 1024 to reduce the chance of blocking on logging under bursts (#1190).
Miscellaneous
- This release is built with Go 1.26.6.
- Dependency updates.
- We detached App-owned state with stream subscriptions to its own blog post. It was part of PostgreSQL stream broker post before, but the mechanism is generic and not only PostgreSQL specific - so it's better to have it separate.
- Base Docker image updated to Alpine 3.24 (#1194).
- See also the corresponding Centrifugo PRO release.
v6.9.1
Centrifugo is an open-source scalable real-time messaging server. It instantly delivers messages to application online users connected over supported transports (WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, WebTransport). Centrifugo is built around channel subscriptions β so it's a user-facing PUB/SUB server.
Centrifugo is language-agnostic and can be used to build chat apps, live comments, multiplayer games, real-time data visualizations, collaborative tools, AI streaming responses, etc. in combination with any backend. It is well suited for modern architectures and allows decoupling the business logic from the real-time transport layer.
Official client SDKs are available for JavaScript (browser, Node.js, React Native), Dart/Flutter, Swift, Java, Python, Go, and .NET. In addition, Centrifugo supports a unidirectional approach for simple use cases with no SDK dependency.
For details, go to the Centrifugo documentation site. For runnable demos see centrifugal/examples.
What's changed
Improvements
- Possibility to choose color accents in admin web UI.
Fixes
- Admin web UI: add previously missing API commands to the web UI β map API (
map_publish,map_remove,map_read_state,map_read_stream,map_stats,map_clear), shared poll API, etc. β and update the embedded web UI (#1184, commit3fc933d9). - Fix a
WARNlog about a missingdevkey on start β some options and flags left over from the dev page removed in v6.9.0 were not fully cleaned up (#1185, commit8cee857f). - Admin: drop the undocumented and unused fallback that read the admin auth token from a
tokenURL query parameter β the token must be supplied via theAuthorizationheader (#1187, commitbc33546f). Addresses GHSA-v4h4-9j4c-ghgp - Removed an unused map
orderedoption (#1186, commit8752f242).
Miscellaneous
β οΈ Reminder: Centrifugo v6.9.0 had breaking changes in server configuration.- Docs: expanded the load balancing chapter with configs for Envoy, Caddy, and Traefik (in addition to Nginx and HAProxy) β all validated in a playground running two nodes behind each proxy across every transport (WebSocket, HTTP streaming, SSE) over plaintext and TLS, up to 10k connections.
- Docs: added interactive widgets throughout the documentation to clarify concepts where newcomers get confused most β for example the connection JWT explorer, subscription JWT explorer, channel resolver, subscribe permission model, and interactive proxy explorer.
- This release is built with Go 1.26.5
- Dependency updates
- See also the corresponding Centrifugo PRO release.