github.com/anycable/anycable-go@v1.5.1/docs/reliable_streams.md (about) 1 # Reliable streams and resumable sessions 2 3 Since v1.4, AnyCable allows you to enhance the consistency of your real-time data and go from **at-most-once** to **at-least-once** and even **exactly-once delivery**. 4 5 > 🎥 Learn more about the consistency pitfalls of Action Cable from [The pitfalls of realtime-ification](https://noti.st/palkan/MeBUVe/the-pitfalls-of-realtime-ification) talk (RailsConf 2022). 6 7 ## Overview 8 9 The next-level delivery guarantees are achieved by introducing **reliable streams**. AnyCable keeps a *hot cache* \* of the messages sent to the streams and allows clients to request the missed messages on re-connection. 10 11 In addition to reliable streams, AnyCable v1.4 also introduces **resumable sessions**. This feature allows clients to restore their state on re-connection and avoid re-authentication and re-subscription to channels. 12 13 \* The "hot cache" here means that the cache is short-lived and is not intended to be used as a long-term storage. The primary purpose of this cache is to improve the reliability of the stream delivery for clients with unstable network connections. 14 15 ## Quick start 16 17 The easiest way to try the streams history feature is to use the `broker` preset for AnyCable-Go (named after the underlying component, [Broker](./broker.md)): 18 19 ```sh 20 $ anycable-go --presets=broker 21 22 INFO 2023-04-14T00:31:55.548Z context=main Starting AnyCable 1.4.0-d8939df (with mruby 1.2.0 (2015-11-17)) (pid: 87410, open file limit: 122880, gomaxprocs: 8) 23 INFO 2023-04-14T00:31:55.548Z context=main Using in-memory broker (epoch: vRXl, history limit: 100, history ttl: 300s, sessions ttl: 300s) 24 INFO 2023-04-18T20:46:00.693Z context=pubsub Starting Redis pub/sub: localhost:6379 25 INFO 2023-04-19T16:22:55.776Z context=pubsub provider=http Accept broadcast requests at http://localhost:8090/_broadcast 26 ... 27 ``` 28 29 Now, at the Ruby/Rails side, switch to the `http` or `redisx` broadcasting adapter (if you use Redis). For example, in `config/anycable.yml`: 30 31 ```yaml 32 default: &default 33 # ... 34 broadcast_adapter: http 35 ``` 36 37 Finally, at the client-side, you MUST use the [AnyCable JS client](https://github.com/anycable/anycable-client) and configure it to use the `actioncable-v1-ext-json` protocol: 38 39 ```js 40 import { createCable } from '@anycable/web' 41 // or for non-web projects 42 // import { createCable } from '@anycable/core' 43 44 export default createCable({protocol: 'actioncable-v1-ext-json'}) 45 ``` 46 47 That's it! Now your clients will automatically catch-up with the missed messages and restore their state on re-connection. 48 49 ## Manual configuration 50 51 The `broker` preset is good for a quick start. Let's see how to configure the broker and other components manually. 52 53 First, you need to provide the `--broker` option with a broker adapter name: 54 55 ```sh 56 $ anycable-go --broker=memory 57 58 INFO 2023-04-14T00:31:55.548Z context=main Starting AnyCable 1.4.0-d8939df (with mruby 1.2.0 (2015-11-17)) (pid: 87410, open file limit: 122880, gomaxprocs: 8) 59 INFO 2023-04-14T00:31:55.548Z context=main Using in-memory broker (epoch: vRXl, history limit: 100, history ttl: 300s, sessions ttl: 300s) 60 ... 61 ``` 62 63 Then, you MUST configure a compatible broadcasting adapter (currently, `http` and `redisx` are available). For example, when using Redis: 64 65 ```sh 66 $ anycable-go --broker=memory --broadcast_adapter=redisx 67 68 ... 69 INFO 2023-07-04T02:00:24.386Z consumer=s2IbkM context=broadcast id=s2IbkM provider=redisx stream=__anycable__ Starting Redis broadcaster at localhost:6379 70 ... 71 ``` 72 73 See [broadcasting documentation](./broadcasting.md) for more information. 74 75 Finally, to re-transmit _registered_ messages within a cluster, you MUST also configure a pub/sub adapter (via the `--pubsub` option). The command will look as follows: 76 77 ```sh 78 $ anycable-go --broker=memory --broadcast_adapter=redisx --pubsub=redis 79 80 INFO 2023-07-04T02:02:10.548Z context=main Starting AnyCable 1.4.0-d8939df (with mruby 1.2.0 (2015-11-17)) (pid: 87410, open file limit: 122880, gomaxprocs: 8) 81 INFO 2023-07-04T02:02:10.548Z context=main Using in-memory broker (epoch: vRXl, history limit: 100, history ttl: 300s, sessions ttl: 300s) 82 INFO 2023-07-04T02:02:10.586Z consumer=s2IbkM context=broadcast id=s2IbkM provider=redisx stream=__anycable__ Starting Redis broadcaster at localhost:6379 83 INFO 2023-07-04T02:02:10.710Z context=pubsub Starting Redis pub/sub: localhost:6379 84 ... 85 ``` 86 87 See [Pub/Sub documentation](./pubsub.md) for available options. 88 89 ### Cache settings 90 91 There are several configuration options to control how to store messages and sessions: 92 93 - `--history_limit`: Max number of messages to keep in the stream's history. Default: `100`. 94 - `--history_ttl`: Max time to keep messages in the stream's history. Default: `300s`. 95 - `--sessions_ttl`: Max time to keep sessions in the cache. Default: `300s`. 96 97 Currently, the configuration is global. We plan to add support for granular (per-stream) settings in the following releases. 98 99 ## Resumed sessions vs. disconnect callbacks 100 101 AnyCable WebSocket server notifies a main application about the client disconnection via the `Disconnect` RPC call (which translates into `Connection#disconnect` and `Channel#unsubscribed` calls in Rails). Currently, when the client's session is restored, no callbacks are invoked in the main application. Keep this limitation in mind when designing your business logic (i.e., if you rely on connect/disconnect callbacks, you should consider disabling sessions cache by setting `sessions_ttl` to 0). 102 103 **NOTE:** We consider introducing a new RPC method, `Restore`, along with the corresponding Ruby-side callbacks (`Connection#restored` and `Channel#resubscribed`) to handle this situation. Feel free to join [the discussion](https://github.com/orgs/anycable/discussions/209) and share your thoughts! 104 105 ## Cache backends 106 107 ### Memory 108 109 The default broker adapter. It stores all data in memory. It can be used **only for single node installations**. 110 111 **IMPORTANT**: Since the data is stored in memory, it's getting lost during restarts. 112 113 **NOTE:** Storing data in memory may result into the increased RAM usage of an AnyCable-Go process. 114 115 ### NATS 116 117 _🧪 This adapter is currently in the experimental stage. Please, report any issues you may encounter._ 118 119 This adapter uses [NATS JetStream](https://nats.io/) as a shared distributed storage for sessions and streams cache and also keeps a local snapshot in memory (using the in-memory adapter described above). 120 121 Usage: 122 123 ```sh 124 $ anycable-go --broker=nats --nats_servers=nats://localhost:4222 125 126 INFO 2023-10-28T00:57:53.937Z context=main Starting AnyCable 1.4.6-c31c153 (with mruby 1.2.0 (2015-11-17)) (pid: 29874, open file limit: 122880, gomaxprocs: 8) 127 INFO 2023-10-28T00:57:53.937Z context=main Starting NATS broker: nats://localhost:4222 (history limit: 100, history ttl: 300s, sessions ttl: 300s) 128 ... 129 ``` 130 131 **NOTE:** You MUST have JetStream enabled in your NATS server. See [NATS JetStream documentation](https://docs.nats.io/nats-concepts/jetstream) for more information. 132 133 ### Using with embedded NATS 134 135 [Embedded NATS](./embedded_nats.md) automatically enables JetStream if the NATS broker is being used: 136 137 ```sh 138 $ anycable-go --embed_nats --broker=nats 139 140 INFO 2023-10-28T00:59:01.177Z context=main Starting AnyCable 1.4.6-c31c153 (with mruby 1.2.0 (2015-11-17)) (pid: 30693, open file limit: 122880, gomaxprocs: 8) 141 INFO 2023-10-28T00:59:01.177Z context=main Starting NATS broker: nats://127.0.0.1:4222 (history limit: 100, history ttl: 300s, sessions ttl: 300s) 142 INFO 2023-10-28T00:59:01.205Z context=main Embedded NATS server started: nats://127.0.0.1:4222 143 ... 144 ``` 145 146 **IMPORTANT:** Your multi-node cluster MUST have at least **3 nodes** to use NATS JetStream. Super-cluster mode hasn't been tested yet. 147 148 ### Redis 149 150 <p class="pro-badge-header"></p> 151 152 AnyCable-Go Pro comes with a Redis-based broker adapter. It stores all data in Redis and, thus, can be used in multi-node installations. 153 154 To use Redis broker, you need to provide the `--broker` option with the `redis` adapter name: 155 156 ```sh 157 $ anycable-go --broker=redis 158 159 INFO 2023-07-08T00:46:55.491Z context=main Starting AnyCable 1.4.0-pro-eed05bc (with mruby 1.2.0 (2015-11-17)) (pid: 78585, open file limit: 122880, gomaxprocs: 8, netpoll: true) 160 INFO 2023-07-08T00:46:55.492Z context=main Using Redis broker at localhost:6379 (history limit: 100, history ttl: 300s, sessions ttl: 300s) 161 ... 162 ``` 163 164 When you use the `broker` preset with AnyCable-Go, it automatically configures the Redis broker (if Redis credentials are configured). 165 166 #### Streams history expiration 167 168 We use [Redis Streams](https://redis.io/docs/data-types/streams/) to store messages history. Redis doesn't support expiring individual messages in a stream, so we expire the whole stream instead. In other words, the `--history_ttl` option controls the expiration of the whole stream. 169 170 ## Further reading 171 172 For in-depth information about the feature and its internals, see the following articles: 173 174 - [Broker](./broker.md) 175 - [Pub/Sub](./pubsub.md)