Client collection out of sync with server

Hi,
I have a map app where I would like to update the markers each time the client moves or zooms the map. The markers to be displayed is in a collection named “Markers”.

I have a session variable “mapbounds” which gets updated each time the map boundaries change. This session variable triggers a subscription named “getMarkers”. The “getMarkers” publish function calls an executable which processes all my nodal data and detemines which nodes to place in the Marker collection. The executable is called using Npm.require(‘child_process’).spawn;

I can confirm that the executable correctly populates the Marker collection on the server.

I plan to plot many markers (1000’s) and hence would like to render them using html5 canvas. Inserting individual markers using observechanges therefore does not seem right (too many DOM elements). I need to draw the whole Marker collection in one go on the canvas.

My problem is that the client does not wait for the executable in the subscription to finish. Hence on the client the Marker collection is empty, while on the server it is populated (I move the map, the session variable triggers the new subscription, the collection appears empty to the client while the executable is busy processing and hence marks the collection on the client side as complete. The executable finishes and updates the Marker collection on the server side, but the client remains ignorant that the collection has changed).

How do I get the subscription on the client to update after the Marker collection on the server has been populated?

Here is my iron-router route
Router.route(‘home’, {
path: ‘/’,
template: ‘leaflettest’,
// subscribe to todos before the page is rendered but don’t wait on the
// subscription, we’ll just render the items as they arrive
onBeforeAction: function () {
console.log(“onBeforeAction”);
if(!Session.get(‘boundsarray’)){ // if no boundsarray, then show the whole world
Session.set(‘boundsarray’, [[-89,-179],[89,179]]);
}
console.log(Session.get(‘modelid’));
console.log(Session.get(‘boundsarray’));
this.markersHandle = Meteor.subscribe(‘getMarkers’, Session.get(‘modelid’), Session.get(‘boundsarray’));

if (this.ready()) {
  // Handle for launch screen defined in app-body.js
  //setNewResult();
  console.log(Markers.find().count());
}
this.next();

},
data: function () {
return Markers.find();
},
action: function () {
console.log(“action”);
this.render();
}
});

Here is my publication:
Meteor.publish(‘getMarkers’, function(modelid,boundsarray){
console.log(‘getMarkers>>’);
var self = this;
console.log(boundsarray);

//var clusterServer = new Future();
Meteor.call('cluster_server',modelid,boundsarray, function(error, result){
    if (error){
        console.log('runquery-cluster_server error>>');
        //clusterServer.return(error);
        console.log(error);
        self.ready();
    } else {
        console.log('runquery-cluster_server result>>');
        console.log(result);
        console.log(Markers.find().count());
        return Markers.find();
        //clusterServer.return(Markers.find());
    }
});

Below is my code to run the executable:
Meteor.methods({
‘cluster_server’:function(modelid,mapBounds){ // GeoJOSN, Mongo [lng,lat]
if(!modelid) {
throw new Meteor.Error(‘no model’,‘No model selected’);
}
if(!mapBounds) {
throw new Meteor.Error(‘no map bounds’,‘No map boundaries set’);
}
console.log(“mapBounds”);
console.log(mapBounds);
var SWLng = mapBounds[0][0];
var SWLat = mapBounds[0][1];
var NELng = mapBounds[1][0];
var NELat = mapBounds[1][1];
var epsilon = 0.01*distance(SWLng, SWLat, NELng, NELat, “K”);
var minpts = 2;
console.log(“epsilon”);
console.log(epsilon);
function run_cmd(cmd, args, callBack ) {
var spawn = Npm.require(‘child_process’).spawn;
var command = spawn(cmd, args);
var resp = “”;
command.stdout.on(‘data’, function (buffer) { resp += buffer.toString(); }); // async event hooks
command.stderr.on(‘data’, function (data) { console.log('stderr: ’ + data); });
command.stdout.on(‘end’, function() { callBack (resp) });
};
run_cmd( “/home/george/Desktop/CLANG/cluster_server/cluster_server”, [modelid, epsilon, minpts, SWLat, SWLng, NELat, NELng], function(text) { console.log (text) }); // GeoJOSN, Mongo [lng,lat]
},

A different approach would be to bypass the subscription and load/cache data manually with a meteor method.