Browser client
Controlling dispatch
When you send a message, the Faye client attempts to resend the message until it receives confirmation that the server has received it. There are a few options available that let you control how and when the client will retry, once it has detected that a message has failed to send.
First, the constructor takes an option called retry
, which sets the amount
of time in seconds that the client will wait between detecting a failed
delivery and retrying the message.
var client = new Faye.Client(url, {retry: 15});
When calling publish()
, the deadline
option specifies how long to wait
before giving up, for example if you call
client.publish('/foo', {text: 'Hi there'}, {deadline: 10});
then the client will not attempt to resend the message any later than 10
seconds after your first publish()
call.
The attempts
option sets how many times the client will try to send a
message before giving up, including the first attempt. For example, this
will make the client try to deliver the message up to 3 times:
client.publish('/foo', {text: 'Hi there'}, {attempts: 3});
Bear in mind that error detection depends somewhat on the transport in use, and these options do not tightly control when your messages will be retried. Faye will make a best effort to ensure delivery of your messages within the parameters you specify.
Advanced customisation
To make the above options work, Faye uses an object called a Scheduler
.
The Faye client is responsible for selecting which transport to use, sending
messages, detecting delivery success and failure, scheduling retries, and
making sure no duplicate messages are sent. But the scheduler gets to decide
if and when each message is sent. If you want full control over this
concern, you can supply your own scheduler.
For example, by default Faye uses fixed-period retries, as controlled by the
retry
option above. But, say you wanted to have exponential backoff. You
can implement that like so:
var BackoffScheduler = function() { Faye.Scheduler.apply(this, arguments); }; BackoffScheduler.prototype = Object.create(Faye.Scheduler.prototype); BackoffScheduler.prototype.getInterval = function() { var interval = this.options.interval, attempts = this.attempts; return interval * Math.pow(2, attempts - 1); }; var client = new Faye.Client(url, {scheduler: BackoffScheduler});
That is, we create a subclass of Faye.Scheduler
and override the
getInterval()
method, which the client uses to decide how long to wait
before the next retry. Then we pass that class into the Client
via the
scheduler
option. Note that this option is a class, not a single object.
Faye creates a separate scheduler to track each message.
When you inherit from Faye.Scheduler
, the class gets the following
instance properties that you can refer to in its methods:
message
– the Bayeux message that the scheduler applies to.attempts
– the number of times the client has tried to deliver the message.options.interval
– the time in seconds to wait between detecting a failed delivery and resending the message.options.timeout
– the time in seconds after which a delivery is considered failed if no response has been received.options.deadline
– aDate
object representing the latest time at which the message should be sent.options.attempts
– the maximum number of times the client should attempt to deliver the message.
The default Faye.Scheduler
class provides the following API, which you may
override any method of.
getInterval()
– should return the time in seconds to wait between detecting a failed delivery and resending the message.getTimeout()
– should return the time in seconds after which a delivery is considered failed if no response has been received.isDeliverable()
– should returntrue
orfalse
to indicate whether the client should attempt to deliver the message. This is called when the client is about to send the message, not when an error has just been detected.send()
– is called by the client just before it attempts to deliver the message.succeed()
– is called by the client when a response is received from the server. This includes responses that are ‘unsuccessful’ within the semantics of Bayeux; it simply means the server received the message and the client will no try sending it again.fail()
– is called when the client decides a delivery has failed, either by an explicitly signalled network error or a timeout.abort()
– is called when the client decides to stop sending the message, becauseisDeliverable()
returnedfalse
.
Note that when you override a method, particularly one of the latter four
command methods, you should call the Faye.Scheduler
method before adding
your own customisation. For example:
BackoffScheduler.prototype.send = function() { Faye.Scheduler.prototype.send.apply(this, arguments); console.log('Sent message:', this.message); };
This also applies to isDeliverable()
; the client’s deadline
and
attempts
options rely on this method and so if the default implementation
returns false
, you should too:
BackoffScheduler.prototype.isDeliverable = function() { var deliverable = Faye.Scheduler.prototype.isDeliverable.apply(this, arguments); if (!deliverable) return false; // your own logic here };
This might seem cumbersome but the intent of this API is to allow applications to gain full control of the decision-making about if and when messages are sent, without having to deal with requests, sockets, timeouts, error detection, or the messaging protocol. This does mean you can render the client’s built-in control options inactive, if you wish.
The scheduler and its support infrastructure is designed to work with almost no knowledge of how Bayeux works, so it can deal exclusively with message delivery in a clean way.
Note that whereas the deadline
and attempts
options to
client.publish()
only affect messages the client publishes, the scheduler
is actually used for all messages the client sends, including the
/meta/subscribe
and /meta/connect
messages it uses to receive data from
the server. The publish()
options are simply convenient sugar; if you
implement your own scheduler you get to control all messages.