connectrpc / connect-swift

The Swift implementation of Connect: Protobuf RPC that works.
https://connectrpc.com/docs/swift/getting-started
Apache License 2.0
98 stars 20 forks source link

No indication of a failing stream message sending in case of internet unavailability #236

Closed dan-zy-y closed 9 months ago

dan-zy-y commented 10 months ago

When internet becomes unavailable, there is no indication message sending through stream's send was unsuccessful

Problem description

When launching a stream, there is no way to handle unsuccessful stream requests due to internet unavailability. Initially I thought that it is handled by throwing an error on send directly. but since send is not asynchronous it can't be handled there. Then I thought that this might be indicated as a complete case in streams results, which unfortunately is also not the case.

Because of those challenges I currently need to use pre-flight internet availability checks to not lose data and store it locally if it can't be sent through the stream. Normally I would remove data locally when I know that it is delivered to the server. In this case, it however is not possible.

In my particular case we are using client only async stream to transfer data to the server. We could of course try to use bidirectional stream to await for server confirmations for each sent event. There would also need to be a handler/manager that would check for response time from the server and indicate that the connection is down when the timeout is reached.

Question

Might I be doing something wrong with the setup that I don't receive a complete result in results stream? Or is it indeed the expected behaviour

Set up

We use a very simple set up of a protocol client:

ProtocolClient(
            httpClient: NIOHTTPClient(
                host: "our host",
                port: "our port"
            ),
            config: .init(
                host: "our host",
                networkProtocol: .grpc,
                codec: ProtoCodec(),
                interceptors: [our interceptors]
            )
        )
rebello95 commented 10 months ago

👋🏽 hey @dan-zy-y, thanks for opening this issue. It looks like there are a few things here, so I'll address them individually below:

I thought that this might be indicated as a complete case in streams results, which unfortunately is also not the case.

Might I be doing something wrong with the setup that I don't receive a complete result in results stream? Or is it indeed the expected behaviour

To make sure I'm understanding correctly, you're hoping to receive an error through the .complete state for a client-only stream when the internet connection goes offline mid-stream, right? If this is the case, it could be because the timeout is set quite high on the stream configuration (such as on the URLSessionConfiguration). If you shorten this timeout, do you receive an error?

The likely preferred solution which we could consider is is to add an underlying keepalive ping which is regularly sent over the stream to verify that the client is indeed able to send/receive data, and to terminate the stream proactively if pings don't come back in a reasonably quick time. This would require server support as well.

Because of those challenges I currently need to use pre-flight internet availability checks to not lose data and store it locally if it can't be sent through the stream. Normally I would remove data locally when I know that it is delivered to the server. In this case, it however is not possible.

In my particular case we are using client only async stream to transfer data to the server. We could of course try to use bidirectional stream to await for server confirmations for each sent event. There would also need to be a handler/manager that would check for response time from the server and indicate that the connection is down when the timeout is reached.

If you need to know whether a request message made it to the server, pre-flight internet connectivity checks would unfortunately still not be enough since (as you know) the stream could hang/terminate if the client goes offline after creating the stream. Using a bidirectional stream where the server acknowledges receipt of a specific message is likely the approach you'll want to take if you require the client to know which of its messages were successfully received by the server. You could achieve this by passing an id to the server in each request message, then having the server send back that same id in a response to acknowledge receipt of that message, for example.

chrispine commented 9 months ago

Closing this due to inactivity, but feel free to reopen if needed!