Reputation: 550
I've got an implementation of SignalR which is being used as a chat client. The problem seems to be that I have a client side timer, that is pinging the server to notify all other clients of a user's status.
In this instance, I have a heartbeat and a latestactivity. The heartbeat hits the server every fifteen seconds or so, and the latestactivity tracks the user's interactivity. These two values are passed to the server so that all other clients can be notified of everyone else's status. Ie: If User A hasn't moved their mouse for over a minute, when their heartbeat hits the server, it'll broadcast to every other user via SignalR that they are now 'away'..
Anyways, I have an issue where there seems to be an exponential increase in SignalR connections the greater the number of user's that connect to the chat app.
This is the source of the client js timer that I suspect is fishy but I'm not sure whY:
define(['jquery', 'underscore', 'backbone'],
function ($, _, Backbone) {
var Timer = Backbone.Model.extend({
defaults: {
interval: 1 * 10 * 1000,
timeout: null
},
initialize: function (options) {
_.bindAll(this, 'start', 'tick', 'stop', 'tickNow');
if (options.interval) {
this.set('interval', options.interval);
}
},
start: function () {
var timer = setTimeout(this.tick, this.get('interval'));
this.set('timeout', timer);
},
tick: function () {
var self = this;
self.trigger('timerexpired', this);
self.start();
},
tickNow: function () {
var self = this;
self.stop();
self.trigger('timerexpired', this);
self.start();
},
stop: function () {
clearTimeout(this.get('timeout'));
}
});
return Timer;
});
Upvotes: 1
Views: 1109
Reputation: 15234
You shouldn't simply pass this.tick
as the first parameter to setTimeout
, because when the tick
method gets executed this
will be bound to the global window
object instead of the Timer
instance.
You should also probably ensure you are not calling start
when the Timer
instance is already running. I would change the following methods like so:
start: function () {
var self = this;
if (this.get('timeout') !== null) {
throw "start must not be called when the Timer is already running";
}
// creating a closure ensures this is bound correctly in tick()
var timer = setTimeout(function () {
self.tick();
}, this.get('interval'));
this.set('timeout', timer);
},
tick: function () {
this.set('timeout', null);
this.trigger('timerexpired', this);
this.start();
},
stop: function () {
clearTimeout(this.get('timeout'));
this.set('timeout', null);
}
The obvious way to check that the Timer is working correctly is to bind a call to console.log to the timerexpired event to make sure the event isn't being triggered more than expected.
You should post the code where you are stopping and starting SignalR connections if you want help determining why the number of concurrent connections is growing out of control.
Upvotes: 0
Reputation: 381
I notice that you are using the this
keyword in the start timer method. It could be that your call to this.tick
call is out of context when it actually fires. Try:
start: function () {
var self = this;
var timer = setTimeout(this.tick, self.get('interval'));
this.set('timeout', timer);
},
In your browser, chuck a breakpoint into the tick
method and check that you are indeed referencing the right timer.
Upvotes: 2
Reputation: 28511
I don't see how the progression would necessarily be exponential, but the linear progression will certainly tend to it. Basically, you have two main things you can do here:
Upvotes: 1