I have been banging my head against the wall here. I watch an event stream for events. When a certain event comes in, I call npm package function and I have it wrapped but still get the ever famous
Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
In my startup thread, I have the function that is generating this error as:
var theComment = fetchCommentAsync(commentAuthor, commentPermlink)
Which has fetchCommentAsync wrapped as this:
var fetchCommentAsync = Meteor.wrapAsync(function(comAuthor, comPerm, callback) {
reddit.api.getContent(comAuthor, comPerm, function(err, result) {
if (err) throw err;
callback(err, result)
})
})
I guess the @robfallows answer should work.
Or wrap your callback with Meteor.bindEnvironment like
const onDone = Meteor.bindEnvironment((err, res) => {/* your stuff here */});
reddit.api.getContent(comAuthor, comPerm, onDone);
You should also know that if you gonna use any Fiber-await logic (like Collection.insert) in 3rd libraries callbacks you have to wrap those callbacks with Fibers (as Meteor.bindEnvironment does)
After this API call happens, I get the data back and I do use some logic with insert and collection management which is why the waiting is important here and needing to get the return from the API.
It was suggested to me to use async/await on Reddit instead of messing with this stuff. Is that a better path to take than trying to wrap these callbacks?
I am working on it now. What is the reddit.api coming from? Here is the actual function call I am using that I need to wait for so not sure where the last wrapAsync parameter comes form.
// wrapAsync
const result = Meteor.wrapAsync(someHandler)() // -> returns result and executes in Fiber.current(). You dont need to pass callback
// bindEnvironment
someHandler(Meteor.bindEnvironment((err, res) => {})) // calls a callback ans executes in Fiber.run()
It’s better to use wrapAsync because its more like modern plain async/await. But make sure your API has a callback as a function last param anyway
Are you still running that inside a callback, as your original post? There’s no need for that - in fact it makes your code more complex. The whole point behind fibers and Promises - especially async/await - is that they remove the requirement for callbacks. Refactoring my code to use your names:
I ran this exact code block you posted in the try/catch and throws the error. Assuming my library maybe was bad, I tried another one for giggles that had a slow API call with the sandard call back and still throws the same error so maybe I am not wrapping the NodeJS library method right. Here is the second library I am trying now that has a slow call back and need to wait for the comment to come back before I move on.
const fetchCommentAsync = Meteor.wrapAsync(steem.api.getContent, steem.api);
try {
const theComment = fetchCommentAsync(commentAuthor, commentPermlink);
// more processing here
} catch (error) {
// some error handling
console.log(error)
}
console.log(result)
[Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.]
There is something else going on here. You need to share more code, or point us to a repo. It should not be this hard. The code you have shown should work correctly.
The library I am using is now in the linked repo. I am ditching the Reddit API and using a more documented platform. Both were running from a streaming API and when a certain operation was detected, I made my next set of API calls which working through this seems like that maybe the cause? Here is the latest full code that I have converted over to the new library linked above. Sorry if I confused this up.
// This is an active stream of events I am listening to
steem.api.streamOperations((err, operations) => {
if (err) {
throw(new Error('Something went wrong with streamOperations method of Steem-js'));
console.log(err);
}
const opType = operations[0];
const op = operations[1];
// When an event comes in, I check to see what op type it is. I am looking for "Comment" types
if ( opType==="comment" )
{
// It is a comment so now I want to fetch teh comment using the getContent call.
var commentAuthor = op.author
var commentPermlink = op.permlink
const fetchCommentAsync = Meteor.wrapAsync(steem.api.getContent, steem.api);
try {
const theComment = fetchCommentAsync(commentAuthor, commentPermlink);
// more processing here
} catch (error) {
// some error handling
console.log(error)
}
console.log(result)
}
}