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)