faqs.md 5.4 KB

FAQs

Logging / Tracing

Is Logging supported?

Logging is supported by providing a Logger from SwiftLog to the relevant configuration object.

For the client:

  • ClientConnection.Builder.withBackgroundActivityLogger allows a logger to be supplied which logs information at the connection level, relating to things such as connectivity state changes, or connection errors.
  • CallOptions allows logger to be specified. It is used to log information at the RPC level, such as changes to the state of the RPC. Any connection level metadata will be attached to the logger so that RPC logs may be correlated with connection level changes.

For the server:

  • Server.Builder.withLogger allows a logger to be specified. It is used as a root logger and is passed down to each accepted connection and in turn each RPC on a connection. The logger is made available in the context of each RPC handler.

Note that gRPC will not emit logs unless a logger is explicitly provided.

How can RPCs be traced?

For the client:

If logger is set in the CallOptions for an RPC then gRPC may attach a request ID to the metadata of that logger. This is determined by the value of requestIDProvider in CallOptions. The options for requestIDProvider include:

  • autogenerated: a new UUID will be generated (default).
  • generated(_:): the provided callback will be called to generate a new ID.
  • userDefined(_:): the provided value will be used. Note: this option should not be set as a default option on a client as all RPCs would used the same ID.
  • none: no request ID will be attached to the logger, this can be useful if a logger already has a request ID associated with it.

If a request ID is attached to the logger's metadata it will use the key grpc_request_id.

If a request ID is provided and the requestIDHeader option is set then gRPC will add the ID to the request headers. By default requestIDHeader is not set.

Client Connection Lifecycle

Is the client's connection long-lived?

The ClientConnection is intended to be used as a long-living connection to a remote peer. It will manage the underlying network resources automatically, creating a connection when necessary and dropping it when it is no longer required. However, the user must close() the connection when finished with it.

The underlying connection may be in any of the following states:

  • Idle: there is no underlying connection.
  • Connecting: an attempt to establish a connection is being made.
  • Ready: the connection has been established, a TLS handshake has completed (if applicable) and the first HTTP/2 settings frame has been received.
  • Transient failure: A transient error occurred either from a ready connection or from a connection attempt. An new connection will be established after some time. (See later sections on connection backoff for more details.)
  • Shutdown: The application requested that the connection be closed, or a connection error occurred and connection re-establishment was disabled. This state is terminal.

The gRPC library documents these states in more details. Note that not all information linked is applicable to gRPC Swift.

How can connection states be observed?

A connectivity state delegate may be set using withConnectivityStateDelegate(_:executingOn:) on the ClientConnection.Builder.

The delegate is called on the DispatchQueue specified by the executingOn parameter. gRPC will create a DispatchQueue if one isn't otherwise specified.

These state changes will also be logged by the backgroundActivityLogger (see above).

When will the connection idle?

The connection will be idled (i.e. the underlying connection closed and moved to the 'idle' state) if there are no outstanding RPCs for 5 minutes (by default). The connection will not be idled if there outstanding RPCs which are not sending or receiving messages. This option may be configured using withConnectionIdleTimeout on the ClientConnection.Builder.

Any RPC called after the connection has idled will trigger a connection attempt.

How can I keep a connection alive?

For long-lived, low-activity RPCs it may be beneficial to configure keepalive. Doing so will periodically send pings to the remote peer. It may also be used to detect unresponsive peers.

See the gRPC Keepalive documentation for details.

RPC Lifecycle

How do I start an RPC?

RPCs are usually started by invoking a method on a generated client. Each generated client relies on an underlying GRPCChannel to provide transport.

RPCs can also be made without a generated client by using AnyServiceClient. This requires the user know the path (i.e. '/echo/Get') and request and response types for the RPC.

Are failing RPCs retried automatically?

RPCs are never automatically retried by gRPC Swift.

The framework cannot determine whether your RPC is idempotent, it is therefore not safe for gRPC Swift to automatically retry RPCs for you.

Deadlines and Timeouts

It's recommended that deadlines are used to enforce a limit on the duration of an RPC. Users may set a time limit (either a deadline or a timeout) on the CallOptions for each call, or as a default on a client. RPCs which have not completed before the time limit will be failed with status code 4 ('deadline exceeded').