1

I got 2 servers, one for the main app and another one for huge tasks.

User -> Server 1 -> Server 2
Server 1: Main app & Easy tasks
Server 2: Huge Tasks

When I call a server 2's function which takes a long time to answer, server 1 receive undefined when server 2 answer a good result. However, if server2's function takes less than 1 minute to answer, server 1 got the result sent by server 2 and then send it back to the client.

Why it doesn't work only for functions which take more than 1 minute to compute ?

Client :

Meteor.call('reporting.default', params.subReport, params, function(error, result) {
    if (result) self.setState({data: result});
    else self.setState({data: error.message});
});

Server 1:

Meteor.methods({
    'reporting.default'(subReport, params) {
        this.unblock();
        return Meteor.callWorker('reporting.' + subReport, Meteor.callId(), params).then((result, error) => { if (error) return error; else return result; }).await();
    },
});

Meteor.worker = DDP.connect('localhost:' + Meteor.settings.heavyTasksServer.port);
Meteor.callWorker = (method, ...myParameters) => new Promise((resolve, reject) => {
    console.log(method + ": REQUEST");
    Meteor.worker.call(method, ...myParameters, (err, res) => {
        if (err) {
            console.log(method + ": ERROR");
            reject(err);
        }
        else {
            console.log(method + ": ANSWER");
            resolve(res);
        }
    });
});

Meteor.callId = function () {
    const d =new Date();
    return d.getUTCFullYear() +""+ (d.getUTCMonth()+1) +""+ d.getUTCDate() +""+ d.getUTCHours() +""+ d.getUTCMinutes() +""+ d.getUTCSeconds() +""+ d.getUTCMilliseconds() + "-" + Meteor.userId();
};

Server 2:

Meteor.methods({
    'reporting.clientsAssets'(callId, params) {
        this.unblock();
        const funcName = "reporting.clientsAssets";
        if (canRunQuery(1, callId, arguments, funcName)) {
            console.log(funcName + ": START");
            const data = reportingClientsAssets(params);
            console.log(funcName + ": END");
            terminateQuery(callId);
            return data;
        }
    }
});
Holgrabus
  • 141
  • 2
  • 9

1 Answers1

0

You could consider an asynchronous model instead of a synchronous one (which is probably timing out).

Let's think about a queuing mechanism... create a collection call jobs (or whatever you prefer), and server 1 creates a record in the job collection with a status of 'ready'.

A timed task (you can use node-cron for this) runs on server 2 say every minute, and looks for jobs with a status of 'ready'. It takes the first one, sets the status to 'running' and then calls the function to do the work.

When that function completes, it sets the status of the task to 'complete'.

You make use of Meteor's reactivity, so that the user can see the status of the job, once it is started, it moves to 'running', and then to 'complete' once it is done. At that point a link may appear so they have access to the data, report or whatever is produced.

No timeout issues with this mechanism, and it's nicely decoupled.

Mikkel
  • 7,693
  • 3
  • 17
  • 31
  • I already thought about that kind of solution. However, it doesn't explain why server 1 receive undefined. I mean, server 1 wait until server 2 answer, even if it takes 3 minutes ... – Holgrabus Jun 28 '19 at 10:22