Server cleanup after a client disconnects

Is there a way to detect when a client disconnects from a meteor server, either by refreshing or navigating away from the page, so that the server can attempt some cleanup?

Answers:

Answer

One technique is to implement a "keepalive" method that each client regularly calls. This assumes you've got a user_id held in each client's Session.

// server code: heartbeat method
Meteor.methods({
  keepalive: function (user_id) {
    if (!Connections.findOne(user_id))
      Connections.insert({user_id: user_id});

    Connections.update(user_id, {$set: {last_seen: (new Date()).getTime()}});
  }
});

// server code: clean up dead clients after 60 seconds
Meteor.setInterval(function () {
  var now = (new Date()).getTime();
  Connections.find({last_seen: {$lt: (now - 60 * 1000)}}).forEach(function (user) {
    // do something here for each idle user
  });
});

// client code: ping heartbeat every 5 seconds
Meteor.setInterval(function () {
  Meteor.call('keepalive', Session.get('user_id'));
}, 5000);
Answer

I think better way is to catch socket close event in publish function.

Meteor.publish("your_collection", function() {
    this.session.socket.on("close", function() { /*do your thing*/});
}

UPDATE:

Newer version of meteor uses _session like this:

this._session.socket.on("close", function() { /*do your thing*/});
Answer

I've implemented a Meteor smart package that tracks all connected sessions from different sessions and detects both session logout and disconnect events, without an expensive keepalive.

https://github.com/mizzao/meteor-user-status

To detect disconnect/logout events, you can just do the following:

UserStatus.on "connectionLogout", (info) ->
  console.log(info.userId + " with session " + info.connectionId + " logged out")

You can also use it reactively. Check it out!

EDIT: v0.3.0 of user-status now tracks users being idle as well!

Answer

if you're using Auth you have access to the user's ID in Method and Publish functions, you could implement your tracking there.. e.g. you could set a "last seen" when the user switches room:

Meteor.publish("messages", function(roomId) {
    // assuming ActiveConnections is where you're tracking user connection activity
    ActiveConnections.update({ userId: this.userId() }, {
        $set:{ lastSeen: new Date().getTime() }
    });
    return Messages.find({ roomId: roomId});
});
Answer

I'm using Iron Router and call my cleanup code on the unload event of my main controller. Sure this will not catch the event of a tab closing, but still feels good enough for many use cases

ApplicationController = RouteController.extend({
    layoutTemplate: 'root',
    data: {},
    fastRender: true,
    onBeforeAction: function () {
        this.next();
    },
    unload: function () {
        if(Meteor.userId())
            Meteor.call('CleanUpTheUsersTrash');
    },
    action: function () {
        console.log('this should be overridden by our actual controllers!');
    }
});

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.