faye/faye-redis-ruby — pull request #10 by jarthod (2014-05-22 14:27:16+00:00)
Title: Fix random 401 errors and missed message in long-polling

When trying faye-redis with my benchmark doing thousands of connection and pushing messages to everyone, I found two issues with faye-redis:

# Random 401

When multiple clients are connecting quickly (handshake + subscribe), faye-redis would sometimes throw a 401 Unknown Client to a freshly connected client.
The reason I found for this is in `create_client`:

```ruby
...
@redis.zadd(@ns + '/clients', 0, client_id) do |added|
...
ping(client_id)
...
end
```
Here we're adding the client to the sorted set, **with a timestamp of 0**, and once this is done, we call `ping`, which will update the timestamp to Time.now. The problem is that `ping` being async, the subscribe call can be processed by the server **before** the timestamp update is processed by redis, so the timestamp is still 0.
If the timestamp is 0, `client_exists` will return false and the server will reject the client.

This is a basic race condition issue, which I fixed by initiating the client timestamp to `get_current_time` instead of 0. This way even if the ping is not processed yet, the client is considered present.

# Missed message in long-polling

The other issue I found is in long polling, my test would almost always hang on missed messages.
The cause is this time in `empty_queue`:

```ruby
return unless @server.has_connection?(client_id)
init
key = @ns + "/clients/#{client_id}/messages"
@redis.multi
@redis.lrange(key, 0, -1)
@redis.del(key)
@redis.exec.callback do |json_messages, deleted|
next unless json_messages
messages = json_messages.map { |json| MultiJson.load(json) }
@server.deliver(client_id, messages)
end
```

Here again we have a race condition, let's say when `empty_queue` is called the server has a connection, but then when the redis call (LRANGE + DEL) is complete, the connection is now lost (because another response was send, or because the timeout expired).
In this case the engine is sending all message to `@server.deliver`.
If no connection is present, `@server.deliver` will simply return false and discard the messages, they are now lost.
I fixed this by simply verifying the return value of `deliver`, and if it is `false`, I push the messages back into the queue so they are delivered on the next connection.

In this pull request I also updated faye submodule, redis config file and other few stuff to get the specs running properly.