当使用来自npm模块(client.call
)的函数node-celery
时,似乎没有执行client.call
的回调函数。
Meteor.methods({
'estimates.request'(data) {
var celery = require('node-celery')
var client = celery.createClient({...})
client.on('connect', function() {
console.log('connected'); // this is executed
client.call('proj.tasks.register', [name],
function(err, result) {
console.log('result: ', result); // this is not executed
client.end();
return result;
}
);
});
}
});
在client.call
中尝试包裹Meteor.wrapAsync
:
callFunc = client.on('connect', function() {
console.log('connected'); // this is executed
client.call('proj.tasks.register', [name],
function(err, result) {
console.log('result: ', result); // this is not executed
client.end();
return result;
}
);
});
callFuncSync = Meteor.wrapAsync(callFunc)
callFuncSync()
但是这会在Meteor服务器控制台中引发错误:
err: [Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.]
err: { [Error: read ECONNRESET] code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }
问题:我们应该如何使用Meteor.bindEnvironment
来解决此问题?
答案 0 :(得分:3)
来自文档,
包装一个以回调函数作为最终参数的函数。包装函数的回调签名应为
function(error, result){}
您的代码只包装事件附件调用的返回值。
你可以包装整个事物(连接+任务调用),但在你的情况下,我建议采用不同的方法:
现在,每当有人调用该方法时,您都会连接到Celery。如果可能的话,我建议与Celery建立持久的联系。
您尝试换行的函数不符合wrapAsync
要求,因此您必须将它们包装在一个函数中。
在以下代码中,连接和调用功能都得到了处理。请注意,这些函数采用cb
参数,将由Meteor提供给它们,并根据需要使用错误和/或结果调用它。
然后将这些函数传递给wrapAsync
。
如果错误传递给回调并且使用光纤模拟同步运行(如果它们以同步方式调用)(即,没有传递回调),则会抛出它们的同步版本。这就是try..catch
阻止的原因。
import { Meteor } from 'meteor/meteor';
const celery = require('node-celery'); // or `import` it
function createAndConnectAsync(details, cb) {
const client = celery.createClient(details);
const errHandler = function(e) {
cb(e, client);
};
client.once('connect', function() {
client.off('error', errHandler);
cb(null, client); // success
});
client.once('error', errHandler);
}
function callAsync(client, task, args, cb) {
client.call(task, args, function(result) {
cb(null, result);
});
}
const createAndConnect = Meteor.wrapAsync(createAndConnectAsync);
const call = Meteor.wrapAsync(callAsync);
let client;
try {
client = createAndConnect({...}); // returns after the client is connected
} catch(e) {
// connection error
}
Meteor.methods({
'estimates.request'(data) {
// generate `name`
const result = call(client, 'proj.tasks.register', [name]);
return result;
}
});
答案 1 :(得分:2)
组合异步库可能很棘手,通常它们有一些辅助方法,如Meteor的bindEnvironment。
从Meteor.bindEnvironment返回的函数也会自动在光纤中运行。
Meteor.methods({
'estimates.request'(data) {
var celery = require('node-celery')
var client = celery.createClient({...})
var otherCallback = Meteor.bindEnvironment(function(err, result) {
console.log('result: ', result); // this is not executed
client.end();
return result;
});
var connectCallback = Meteor.bindEnvironment(function() {
console.log('connected'); // this is executed
client.call('proj.tasks.register', [name], otherCallback);
});
client.on('connect', connectCallback);
}
});
仅供参考:未对此进行测试,因为您的示例并非100%完成:)