12

Before I dive into the code, can someone tell me if there is any documentation available for confirmed delivery in Socket.IO?

Here's what I've been able to glean so far:

  1. A callback can be provided to be invoked when and if a message is acknowledged
  2. There is a special mode "volatile" that does not guarantee delivery
  3. There is a default mode that is not "volatile"

This leaves me with some questions:

  1. If a message is not volatile, how is it handled? Will it be buffered indefinitely?
  2. Is there any way to be notified if a message can't be delivered within a reasonable amount of time?
  3. Is there any way to unbuffer a message if I want to give up?

I'm at a bit of a loss as to how Socket.IO can be used in a time sensitive application without falling back to volatile mode and using an external ACK layer that can provide failure events and some level of configurability. Or am I missing something?

Dave Causey
  • 13,098
  • 7
  • 30
  • 26
  • Below is what I've been able to gather by skimming through the code. Please don't take it as authoritative - I may be flat out wrong in some cases. – Dave Causey Jul 31 '12 at 16:14
  • Socket.IO does not resend any data. The underlying transport (ie, TCP) has its own resend mechanisms, but Socket.IO does not expose any control over them. – Dave Causey Jul 31 '12 at 16:18
  • When a (non-volatile) message is sent on a "socket" with a transport that is not open, the message is placed into a queue to be sent when the transport is opened. There doesn't seem to be any limit on the time a message can be queued, though the queue is cleared when the "socket" itself is closed. – Dave Causey Jul 31 '12 at 16:24
  • If a message requires acknowledgement (callback), an entry is added to a hash table mapping the message id to its callback function. When and if an acknowledge packet is returned, the callback is then invoked. If either the message itself or the acknowledgement is dropped, the callback will never fire. – Dave Causey Jul 31 '12 at 16:28
  • As far as I can tell, the callback hash for a "socket" is never cleaned up whether the ack is received or not. I would expect this to be a serious problem unless there's something I'm missing. – Dave Causey Jul 31 '12 at 16:31
  • In volatile mode, packets are dropped instead of queued if the transport is not open. Also, if the transport buffer is not drained (other packets are waiting to be sent), the volatile packet is dropped. – Dave Causey Jul 31 '12 at 16:35
  • In conclusion, reliable ACK/NACK is outside the scope of Socket.IO as it is implemented. Without some form of time-limited delivery failure notification, the builtin ack mechanism is of little value. I plan to use Socket.IO with some external ACK/NACK logic. – Dave Causey Jul 31 '12 at 16:57
  • Why haven't you posted it as an answer? SO recommends against long discussions in comments. And this should be the accepted answer for this question. – lorefnon Jul 06 '13 at 08:05
  • 1
    It's been almost a year since I posted this question, and it appears no one has anything to add about this topic. I was hoping to elicit some feedback from someone more knowledgeable about Socket.IO. You can take the notes above for the wind-pissing that they are, but at the moment I don't have any idea how accurate or relevant my conclusion was then or now. As far as I'm concerned, this is an unanswered question. – Dave Causey Jul 16 '13 at 19:07

2 Answers2

13

TL;DR You can't have reliable confirmed delivery unless you're willing to wait until the universe dies.


The delivery confirmation you seek is related to the theoretical Two Generals Problem, which is also discussed in this SO answer.

TCP manages the reliability problem by guaranteeing delivery after infinite retries. We live in a finite universe, so the word "guarantee" is theoretically dubious :-)

Theory aside, consider this: engine.io, the underpinnings of socket.io 1.x, uses the following transports:

  • WebSocket
  • FlashSocket
  • XHR polling
  • JSONP polling

Each of those transports is based upon TCP, and TCP is reliable. So as long as connections stay connected and transports don't change, each individual socket.io message or event should be reliable. However, two things can happen on the fly:

  1. engine.io can change transports
  2. socket.io can reconnect in case the underlying transport disconnects

So what happens when a client or your server squirts off a few messages while the plumbing is being fiddled with like that? It doesn't say in either the engine.io protocol or the socket.io protocol (at versions 3 and 4, respectively, as of this writing).

As you suggest in your comments, there is some acknowledgement logic in the implementation. But even simple digital communications has notrivial behavior, so I do not trust an unsupervised socket.io connection for reliable delivery for mission- or safety-critical operations. That won't change until reliable delivery is part of their protocol and their methods have been independently and formally verified.

You're welcome to adopt my policies:

  • Number my messages
  • Ask for a resend when in doubt
  • Do not mutate my state - client or server - unless I know I'm ready

In Short:

Guaranteed message delivery acknowledgement is proven impossible, but TCP guarantees delivery and order given "infinite" retries. I'm less confident about socket.io messages, but they're really powerful and easy to use so I just use them with care.

Community
  • 1
  • 1
kdbanman
  • 10,161
  • 10
  • 46
  • 78
  • 3
    +1 for "You can't have reliable confirmed delivery unless you're willing to wait until the universe dies." – vishal Nov 19 '19 at 12:20
0

I ensured delivery using different strategies

  1. I send data using socket including nonce in the message to prevent repeated message errors
  2. The other party sends a confirmation of recived meassage or i resend after x seconds
  3. I used a REST call by the client every 30 seconds to request all new messages sent by server to catch any dropped messages during transport
kabapy
  • 169
  • 2
  • 7