github.com/anycable/anycable-go@v1.5.1/docs/rpc.md (about)

     1  # AnyCable RPC
     2  
     3  AnyCable allows you to control all the real-time communication logic from your backend application. For that, AnyCable uses a _remote procedure call_ (RPC) mechanism to delegate handling of connection lifecycle events and processing of incoming messages (subscriptions, arbitrary actions).
     4  
     5  Using RPC is required if you design your real-time logic using _Channels_ (like in Rails Action Cable). For primitive pub/sub, you can run AnyCable in a [standalone mode](./getting_started.md#standalone-mode-pubsub-only), i.e., without RPC.
     6  
     7  ## RPC over gRPC
     8  
     9  AnyCable is built for performance. Hence, it defaults to gRPC as a transport/protocol for RPC communication.
    10  
    11  By default, AnyCable tries to connect to a gRPC server at `localhost:50051`:
    12  
    13  ```sh
    14  $ anycable-go
    15  
    16  2024-03-06 14:09:23.532 INF Starting AnyCable 1.5.0-4f16b99 (with mruby 1.2.0 (2015-11-17)) (pid: 21540, open file limit: 122880, gomaxprocs: 8) nodeid=6VV3mO
    17  ...
    18  2024-03-06 14:09:23.533 INF RPC controller initialized: localhost:50051 (concurrency: 28, impl: grpc, enable_tls: false, proto_versions: v1) nodeid=6VV3mO context=rpc
    19  ```
    20  
    21  You can change this setting by providing `--rpc_host` option or `ANYCABLE_RPC_HOST` env variable.
    22  
    23  [AnyCable Ruby][anycable-ruby] library comes with AnyCable gRPC server out-of-the-box.
    24  
    25  For other platforms, you can use definitions for the AnyCable gRPC service ([rpc.proto][proto]) to write your custom RPC server.
    26  
    27  ## RPC over HTTP
    28  
    29  AnyCable also supports RPC communication over HTTP. It's a good alternative if you don't want to deal with separate gRPC servers or you are using a platform that doesn't support gRPC (e.g., Heroku, Google Cloud Run).
    30  
    31  To connect to an HTTP RPC server, you must specify the `--rpc_host` (or `ANYCABLE_RPC_HOST`) with the explicit `http://` (or `https://`) scheme:
    32  
    33  ```sh
    34  $ anycable-go --rpc_host=http://localhost:3000/_anycable
    35  
    36  2024-03-06 14:21:37.231 INF Starting AnyCable 1.5.0-4f16b99 (with mruby 1.2.0 (2015-11-17)) (pid: 26540, open file limit: 122880, gomaxprocs: 8) nodeid=VkaKtV
    37  ...
    38  2024-03-06 14:21:37.232 INF RPC controller initialized: http://localhost:3000/_anycable (concurrency: 28, impl: http, enable_tls: false, proto_versions: v1) nodeid=VkaKtV context=rpc
    39  ```
    40  
    41  [AnyCable Ruby][anycable-ruby] library allows you to mount AnyCable HTTP RPC right into your Rack-compatible web server.
    42  
    43  [AnyCable JS][anycable-server-js] provides HTTP handlers for processing HTTP RPC requests.
    44  
    45  For other platforms, check out our Open API specification with examples on how to implement AnyCable HTTP RPC endpoint yourself:  [anycable.spotlight.io](https://anycable.stoplight.io).
    46  
    47  ### Configuration and security
    48  
    49  If HTTP RPC endpoint is open to public (which is usually the case, since HTTP RPC is often embedded into the main application web server), it MUST be protected from unauthorized access.
    50  
    51  AnyCable can be configured to pass an authentication key along RPC requests in the `Authorization: Bearer <secret key>` header.
    52  
    53  You can either configure the RPC server key explicitly via the `--http_rpc_secret` (or `ANYCABLE_HTTP_RPC_SECRET`) parameter or use the application secret (`--secret`) to generate one using the following formula (in Ruby):
    54  
    55  ```ruby
    56  rpc_secret_key = OpenSSL::HMAC.hexdigest("SHA256", "<APPLICATION SECRET>", "rpc-cable")
    57  ```
    58  
    59  Alternatively, using `openssl`:
    60  
    61  ```sh
    62  echo -n 'rpc-cable' | openssl dgst -sha256 -hmac '<your secret>' | awk '{print $2}'
    63  ```
    64  
    65  If you use official AnyCable libraries at the RPC server side, you don't need to worry about these details yourself (the shared application secret is used to generate tokens at both sides). Just make sure both sides share the same application or HTTP RPC secret.
    66  
    67  Other available configuration options:
    68  
    69  - `http_rpc_timeout`: timeout for HTTP RPC requests (default: 3s).
    70  
    71  ## Concurrency settings
    72  
    73  AnyCable uses a single Go gRPC client\* to communicate with AnyCable RPC servers (see [the corresponding PR](https://github.com/anycable/anycable-go/pull/88)). We limit the number of concurrent RPC calls to avoid flooding servers (and getting `ResourceExhausted` exceptions in response).
    74  
    75  \* A single _client_ doesn't necessary mean a single connection; a Go gRPC client could maintain multiple HTTP2 connections, for example, when using [DNS-based load balancing](../deployment/load_balancing).
    76  
    77  We limit the number of concurrent RPC calls at the application level (to prevent RPC servers overload). By default, the concurrency limit is equal to **28**, which is intentionally less than the default RPC pool size of **30** (for example, in Ruby gRPC server implementation): there is a tiny lag between the times when the response is received by the client and the corresponding worker is returned to the pool. Thus, whenever you update the concurrency settings, make sure that the AnyCable value is _slightly less_ than one we use by default for AnyCable Ruby gRPC server.
    78  
    79  You can change this value via `--rpc_concurrency` (`ANYCABLE_RPC_CONCURRENCY`) parameter.
    80  
    81  ### Adaptive concurrency
    82  
    83  <p class="pro-badge-header"></p>
    84  
    85  AnyCable Pro provides the **adaptive concurrency** feature. When it is enabled, AnyCable automatically adjusts its RPC concurrency limit depending on the two factors: the number of `ResourceExhausted` errors (indicating that the current concurrency limit is greater than RPC servers capacity) and the number of pending RPC calls (indicating the current concurrency is too small to process incoming messages). The first factor (exhausted errors) has a priority (so if we have both a huge backlog and a large number of errors we decrease the concurrency limit).
    86  
    87  You can enable the adaptive concurrency by specifying 0 as the `--rpc_concurrency` value:
    88  
    89  ```sh
    90  $ anycable-go --rpc_concurrency=0
    91  
    92  ...
    93  
    94  2024-03-06 14:21:37.232 INF RPC controller initialized: \
    95    localhost:50051 (concurrency: auto (initial=25, min=5, max=100), enable_tls: false, proto_versions: v1) \
    96    nodeid=VkaKtV context=rpc
    97  ```
    98  
    99  You should see the `(concurrency: auto (...))` in the logs. You can also specify the upper and lower bounds for concurrency via the following parameters:
   100  
   101  ```sh
   102  $ anycable-go \
   103    --rpc_concurrency=0 \
   104    --rpc_concurrency_initial=30 \
   105    --rpc_concurrency_max=50 \
   106    --rpc_concurrency_min=5
   107  ```
   108  
   109  You can also monitor the current concurrency value via the `rpc_capacity_num` metrics. Read more about [AnyCable instrumentation](./instrumentation.md).
   110  
   111  [proto]: ../misc/rpc_proto.md
   112  [anycable-ruby]: https://github.com/anycable/anycable
   113  [anycable-server-js]: https://github.com/anycable/anycable-serverless-js