Javascript 在服务器上调用 Collection.insert 时,“流星代码必须始终在 Fiber 中运行”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10192938/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Meteor code must always run within a Fiber" when calling Collection.insert on server
提问by Andrew Beresford
I have the following code in server/statusboard.js;
我在 server/statusboard.js 中有以下代码;
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);
});
Basically, it's pulling some data from a JSON feed and trying to push it into a collection.
基本上,它从 JSON 提要中提取一些数据并尝试将其推送到集合中。
When I start up Meteor I get the following exception;
当我启动 Meteor 时,出现以下异常;
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
I'm not too sure what that error means. Does anyone have any ideas, or can suggest a different approach?
我不太确定那个错误是什么意思。有没有人有任何想法,或者可以提出不同的方法?
采纳答案by Zeman4323
As mentioned above it is because your executing code within a callback.
如上所述,这是因为您在回调中执行代码。
Any code you're running on the server-side needs to be contained within a Fiber.
您在服务器端运行的任何代码都需要包含在 Fiber 中。
Try changing your getServices function to look like this:
尝试将您的 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();
}
I just ran into a similar problem and this worked for me. What I have to say though is that I am very new to this and I do not know if this is how this should be done.
我刚刚遇到了类似的问题,这对我有用。不过我要说的是,我对此很陌生,我不知道这是否应该这样做。
You probably could get away with only wrapping your insert statement in the Fiber, but I am not positive.
您可能可以只将插入语句包装在 Fiber 中,但我并不乐观。
回答by imslavko
Just wrapping your function in a Fiber might not be enough and can lead to unexpected behavior.
仅将您的函数包装在 Fiber 中可能还不够,并且可能导致意外行为。
The reason is, along with Fiber, Meteor requires a set of variables attached to a fiber. Meteor uses data attached to a fiber as a dynamic scope and the easiest way to use it with 3rd party api is to use Meteor.bindEnvironment
.
原因是,与 Fiber 一起,Meteor 需要一组附加到 Fiber 的变量。Meteor 使用附加到光纤的数据作为动态范围,将它与 3rd 方 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'); }));
Watch these videos on evented mind if you want to know more: https://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variableshttps://www.eventedmind.com/posts/meteor-what-is-meteor-bindenvironment
如果您想了解更多信息,请观看这些视频:https ://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variables https://www.eventedmind.com/posts/meteor-什么是流星绑定环境
回答by Steeve Cannon
Based on my tests you have to wrap the insert in code I tested that is similar to the above example.
根据我的测试,您必须将插入内容包装在我测试过的与上述示例类似的代码中。
For example, I did this and it still failed with Fibers error.
例如,我这样做了,但它仍然因 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();
}
}
I did this and it ran fine with no errors.
我这样做了,它运行良好,没有错误。
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?
}
}
);
}
}
I thought this might help others encountering this issue. I have not yet tested calling the asynchy type of external service after internal code and wrapping that in a Fiber. That might be worth testing as well. In my case I needed to know the remote action happened before I do my local action.
我认为这可能会帮助其他人遇到这个问题。我还没有测试在内部代码之后调用异步类型的外部服务并将其包装在 Fiber 中。这也可能值得测试。就我而言,我需要在执行本地操作之前知道远程操作发生了。
Hope this contributes to this question thread.
希望这有助于这个问题线程。