"Meteor code must always run within a Fiber" when calling Collection.insert on server
Just wrapping your function in a Fiber might not be enough and can lead to unexpected behavior.
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
.
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
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.
Try changing your getServices function to look like this:
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.
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.
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.
Hope this contributes to this question thread.