Вопрос по javascript – «Метеоритный код всегда должен выполняться внутри оптоволокна» при вызове Collection.insert на сервере
У меня есть следующий код в server / statusboard.js;
<code>var require = __meteor_bootstrap__.require, request = require("request") function getServices(services) { services = []; request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) { var resJSON = JSON.parse(body); _.each(resJSON, function(data) { var host = data["host_name"]; var service = data["service_description"]; var hardState = data["last_hard_state"]; var currState = data["current_state"]; services+={host: host, service: service, hardState: hardState, currState: currState}; Services.insert({host: host, service: service, hardState: hardState, currState: currState}); }); }); } Meteor.startup(function () { var services = []; getServices(services); console.log(services); }); </code>
По сути, он извлекает некоторые данные из фида JSON и пытается поместить их в коллекцию.
Когда я запускаю Meteor, я получаю следующее исключение;
<code>app/packages/livedata/livedata_server.js:781 throw exception; ^ Error: Meteor code must always run within a Fiber at [object Object].withValue (app/packages/meteor/dynamics_nodejs.js:22:15) at [object Object].apply (app/packages/livedata/livedata_server.js:767:45) at [object Object].insert (app/packages/mongo-livedata/collection.js:199:21) at app/server/statusboard.js:15:16 at Array.forEach (native) at Function.<anonymous> (app/packages/underscore/underscore.js:76:11) at Request._callback (app/server/statusboard.js:9:7) at Request.callback (/usr/local/meteor/lib/node_modules/request/main.js:108:22) at Request.<anonymous> (/usr/local/meteor/lib/node_modules/request/main.js:468:18) at Request.emit (events.js:67:17) Exited with code: 1 </code>
Я не очень уверен, что означает эта ошибка. У кого-нибудь есть идеи или можно предложить другой подход?
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
Я думаю, потому что это в обратном вызове, нет способа проверить в данный момент для вас.
jonathanKingston
что может привести к неожиданному поведению.
Причина в том, что, наряду с Fiber, Meteor требует набора переменных, привязанных к волокну. Метеор использует данные, прикрепленные к оптоволокну, в качестве динамического диапазона, и самый простой способ использовать его с API стороннего производителя - это использоватьMeteor.bindEnvironment
.
T.post('someurl', Meteor.bindEnvironment(function (err, res) {
// do stuff
// can access Meteor.userId
// still have MongoDB write fence
}, function () { console.log('Failed to bind environment'); }));
Посмотрите эти видео, чтобы узнать больше: https://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variables https://www.eventedmind.com/posts/meteor-what-is-meteor-bindenvironment
вы должны заключить вставку в код, который я тестировал, аналогично приведенному выше примеру.
Например, я сделал это, и это все еще не удалось с ошибкой Fibers.
function insertPost(args) {
if(args) {
Fiber(function() {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}).run();
}
}
Я сделал это, и он работал нормально, без ошибок.
function insertPost(args) {
if(args) {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
Fiber(function() {
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}).run();
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}
}
Я думал, что это может помочь другим, сталкивающимся с этой проблемой. Я еще не проверял вызов асинхронного типа внешнего сервиса после внутреннего кода и его перенос в Fiber. Это также может стоить проверить. В моем случае мне нужно было знать, что удаленное действие произошло до того, как я выполню свое локальное действие.
Надеюсь, что это способствует этой ветке вопроса.
это потому, что вы выполняете код в обратном вызове.
Любой код, который вы выполняете на стороне сервера, должен содержаться в волокне.
Попробуйте изменить функцию getServices, чтобы она выглядела следующим образом:
function getServices(services) {
Fiber(function() {
services = [];
request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) {
var resJSON = JSON.parse(body);
_.each(resJSON, function(data) {
var host = data["host_name"];
var service = data["service_description"];
var hardState = data["last_hard_state"];
var currState = data["current_state"];
services+={host: host, service: service, hardState: hardState, currState: currState};
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
});
});
}).run();
}
Я просто столкнулся с подобной проблемой, и это сработало для меня. Однако я должен сказать, что я очень новичок в этом, и я не знаю, так ли это нужно делать.
Вы, вероятно, могли бы сойти с рук, только обернув свое выражение вставки в Fiber, но я не уверен.