On Sat, Jul 14, 2012 at 11:15 AM, <jco...@gmail.com
> I'm the author of Faye (which SockJS uses the WebSocket implementation
Hi! Yup, thanks for your great work!
SockJS detects working transports before marking the connection
as open. Engine.io will immediately open the connection and upgrade
The main rationale AFAICT: flash, one of the Engine.io fallbacks
(and _not_ present in SockJS) loads slowly and in environments
behind proxies takes 3 seconds to timeout.
In previous socket.io
architecture this meant at least 3 seconds delay
for some users. In new engine.io
this can happen without affecting
SockJS doesn't use flash and therefore doesn't need to work around
> * why there needs to be any interruption in service if using an upgrade
> approach, given Faye's approach I described
Maybe I'm getting it wrong, but if you have two established bidirectional
connections, in order to pass control between them, you need some
synchronization mechanism. It should mark that:
- this (old) connection is getting retired, please use new one.
IMO this needs to be synchronous - both sides need to agree
that the old connection is flushed, all messages were indeed delivered
correctly and can be closed. New messages will be sent over
the new one connection from that moment. Something like:
1) normal (old) connection established
2) messages are being exchanged
3) new connection gets established
4) the client says: I'd like to use new connection please.
5) the client should stop sending messages for a time
6) the server hears 4) and sends response: okay, let's use the new one
7) the server stops sending messages
8) the old connection is terminated
9) the client resumes sending messges on the new connection
10) the server after hearing a message resumes sending messages over
the new connection.
Basically: stopping sending messages is required
to avoid a race condition when messages on the new
connection arrive before handover message and possibly
before older messages on the old connection.
> Why is there necessarily any phase during which you cannot send messages?
To avoid a race when one connection is faster than the other.
In other words: if you have a single connection, you have
ordering. With two connections established you can't
reason about ordering at all. You need an explicit synchronization.
>> In ideal world the time of "doesn't work" moments should be equal
>> for both projects. I do prefer consistent behaviour. Once SockJS
>> connection is established, it's done. Latency and performance should
>> be predictable from now on. And, btw, SockJS connection establishment
>> is quite fast, even in complex cases.
> Minor point, but could you clarify what is meant by a 'connection' here in
> terms of the wire protocol. If we're talking about the transport layer, very
> often 'connection' does not seem like the right word (i.e. if using a
> request-response transport).
Yup. "SockJS session" would be a better phrase in this context. Sorry.
> I think of it more like, at all times the
> client has an object it can use to send/receive data with the server, and
> the client should not be given such an object unless the transport selection
> process has proven the object works.
>> - The "upgrade" idea is likely to be racy - that's why
>> during the upgrade the "working" transport must be stopped.
> What race conditions can occur, and why must work be stopped? The biggest
> race I see in Faye is that it cannot select WebSocket as fast as you'd like,
> and so the first events are delivered over long-polling. This is due to the
> async transport selection process, but it doesn't not stop the client from
> working for any length of time, it's just sub-optimal.
The race I talked about earlier. There may be ways to avoid it,
like to buffer messages all the messages on the new connection
until the confirmation of connection passover is received on the old
In such case one should need to think about:
a) old connection failing before this passover message is received
b) Is this buffer a possible DoS vector?
c) when to close the old connection and who is responsible for it.
I'm not arguing it's all non-solvable (although Engine.io
does not try to solve this - they are using an explicit synchronization
AFAICT). I'm merely saying:
SockJS approach of a having the transport detection before
session establishment is is way simpler, and I can't see any
reason why it could be inferior.
>> - I find the "upgrade" way to be more complicated to implement.
> I'd like more info on this -- what did you find hard, and how do the two
> approaches differ?
I think I've already covered this.
>> But, if you think of using flash fallback - doing 'upgrade' thing
>> makes sense - flash is slow to start _and_ flash will take few
>> seconds to timeout in proxied environments (corporations).
>> If only the jsonp didn't have to be stopped during the flash transport
>> probing doing the 'update' would make sense.
> Is it the case that you need to stop JSON-P because it's hogging a network
> connection, or because of execution guarantees etc? We had a problem in Faye
> ages ago where JSON-P would block execution of other downloaded scripts,
> because Firefox guarantees scripts execute in the order they're inserted.
Interesting. I think I was relating to particular engine.io
Engine.io-client sends 'upgrade' packet, and waits for a response. During this
time client can't communicate.
> This can be mitigated to some extent by:
> * Trying to avoid using JSON-P if you possibly can
> * Making the server end any open JSON-P polling request whenever it receives
> any other request from the same client, to allow the response from the
> second request to execute sooner
>> Though AFAIK, when a fallback is probed previous transport must be
>> stopped (in order to avoid races). So the whole benefit
>> vanishes and engine.io
stops for a few seconds to detect
>> that flash doesn't work.
>> (please, can someone tell me that is not true?)
> I'd like to know if the fact that I've not seen any of these problems is
> connect with the fact that Faye doesn't use Flash. I don't understand the
> additional problems it introduces very well.
I'm sure you have some kind of synchronization that ensures
there aren't any outstanding messages in the old connection
before switching to a new one, and that ensures message
ordering is preserved.
Hope that helps,