An exception throwing when I query db from Iron Router - meteor

Something strange here with Meteor 1.2.1 and Iron Router 1.0.12.
Router.route('/news/:_id', function() {
this.render('l_basic');
console.log (newsCollection.findOne().title);
});
This works perfect. I’ve got the title of my last post in the console.
But there is an unwanted exception too. No matter where I would place database query: into the main router function, to the onAfterAction or any other hook. Doesn't matter, if I'll surround it with if (this.ready()).
If I comment console.log statement, no exception appears.
This is what I get in console. I've completely broken my head, trying to find out what is going on here.
Exception in callback of async function: http://localhost:3000/app/both/router.js?4bb8a45e172aaff7cfe3c5a6bff0f87a62d217d0:17:59
boundNext#http://localhost:3000/packages/iron_middleware-stack.js?3370bd57ef7b310cca3f5dddb11b77fafdcfc1eb:418:35
http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:27
onRerun#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:515:13
boundNext#http://localhost:3000/packages/iron_middleware-stack.js?3370bd57ef7b310cca3f5dddb11b77fafdcfc1eb:418:35
http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:27
onRun#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:499:15
boundNext#http://localhost:3000/packages/iron_middleware-stack.js?3370bd57ef7b310cca3f5dddb11b77fafdcfc1eb:418:35
http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:27
dispatch#http://localhost:3000/packages/iron_middleware-stack.js?3370bd57ef7b310cca3f5dddb11b77fafdcfc1eb:442:7
_runRoute#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:538:17
dispatch#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:848:27
route#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:705:19
boundNext#http://localhost:3000/packages/iron_middleware-stack.js?3370bd57ef7b310cca3f5dddb11b77fafdcfc1eb:418:35
http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:27
boundNext#http://localhost:3000/packages/iron_middleware-stack.js?3370bd57ef7b310cca3f5dddb11b77fafdcfc1eb:365:18
http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:27
dispatch#http://localhost:3000/packages/iron_middleware-stack.js?3370bd57ef7b310cca3f5dddb11b77fafdcfc1eb:442:7
http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:385:21
_compute#http://localhost:3000/packages/tracker.js?7776276660c988c38fed448d8262b925dffb5bc3:349:36
Computation#http://localhost:3000/packages/tracker.js?7776276660c988c38fed448d8262b925dffb5bc3:237:18
autorun#http://localhost:3000/packages/tracker.js?7776276660c988c38fed448d8262b925dffb5bc3:588:34
http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:383:17
nonreactive#http://localhost:3000/packages/tracker.js?7776276660c988c38fed448d8262b925dffb5bc3:615:13
dispatch#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:382:19
dispatch#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:1692:22
onLocationChange#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:1776:33
_compute#http://localhost:3000/packages/tracker.js?7776276660c988c38fed448d8262b925dffb5bc3:349:36
Computation#http://localhost:3000/packages/tracker.js?7776276660c988c38fed448d8262b925dffb5bc3:237:18
autorun#http://localhost:3000/packages/tracker.js?7776276660c988c38fed448d8262b925dffb5bc3:588:34
start#http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:1769:43
http://localhost:3000/packages/iron_router.js?c564289eeaa191561eba900052037432ebfcbe4a:972:21
withValue#http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:971:21
http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:428:54
http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:27
onGlobalMessage#http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:365:23

Here is some helpful documentation on managing subscriptions for Iron Router.
I'm pretty sure your findOne() is returning undefined at this point, which means your findOne().title is going to throw an exception. You'll want to use waitOn() to get your subscriptions ready before querying data.

Thanks to Stephen Woods I found that my initial code printed both the exception and the title just because of reactivity. And everything I had to do is wait for subscriptions from iron:router.
Router.route('/news/:_id', function() {
this.render('l_basic');
console.log (newsCollection.findOne().title);
}, {
waitOn: function () {
return Meteor.subscribe('news');
});

Related

redux-saga and firebase - Can't log the user out in a clean way

As a preface, let me mention that I have never used redux-saga or Firebase before today. I'm currently playing around to get a feel for both technologies.
I'm probably just missing a small concept, but I can't seem to get signout to work on my app. I figured that I should probably use call() to manage side effects within a saga, but nothing does the trick.
Here's the saga in question:
export function* deauthenticateUser() {
yield takeLatest(DEAUTHENTICATE_REQUEST, function* () {
try {
yield call(firebase.auth().signOut)
yield put({ type: DEAUTHENTICATE })
}
catch (error) {
yield put({
type: DEAUTHENTICATE_FAILURE,
payload: error,
error: true,
})
}
})
}
I confirmed that calling firebase.auth().signout() directly works, it's only when using call() that I get the error action. Note that there's also no payload when the error gets dispatched.
I checked in Firebase's documentation, and apparently firebase.auth().signout() returns a promise with nothing as it's content. I'm starting to wonder if that wouldn't be the problem, maybe redux-saga does not like having no result in it's promise when using call()?
How would one handle authentication and especially logging out with Firebase and redux-saga?
From a comment from NULL SWEΔT, I had to call yield call([firebase.auth(), firebase.auth().signOut]).
The reason for this is because of JS' context and how this works. More details by reading this and this (read documentation for call([context, fn], ...args)).

Meteor [Error: Can't wait without a fiber] after a call to Email.send

I've created a very simple server using Meteor, to send an email after a timeout. When I use a timeout, the message is successfully sent but an error is thrown: [Error: Can't wait without a fiber].
Here's my code:
if (Meteor.isServer) {
Meteor.startup(function () {
// <DUMMY VALUES: PLEASE CHANGE>
process.env.MAIL_URL = 'smtp://me%40example.com:PASSWORD#smtp.example.com:25';
var to = 'you#example.com'
var from = 'me#example.com'
// </DUMMY>
//
var subject = 'Message'
var message = "Hello Meteor"
var eta_ms = 10000
var timeout = setTimeout(sendMail, eta_ms);
console.log(eta_ms)
function sendMail() {
console.log("Sending...")
try {
Email.send({
to: to,
from: from,
subject: subject,
text: message
})
} catch (error) {
console.log("Email.send error:", error)
}
}
})
}
I understand that I could use Meteor.wrapAsync to create a fiber. But wrapAsync expects there to be a callback to call, and Email.send doesn't use a callback.
What should I do to get rid of the error?
This happens because while your Meteor.startup function runs inside a Fiber (like almost all other Meteor callbacks), the setTimeout you use does not! Due to the nature of setTimeout it will run on the top scope, outside the fiber in which you defined and/or called the function.
To solve, you could use something like Meteor.bindEnvironment:
setTimeout(Meteor.bindEnvironment(sendMail), eta_ms);
And then do so for every single call to setTimeout, which is a painfully hard fact.
Good thing it's not actually true. Simply use Meteor.setTimeout instead of the native one:
Meteor.setTimeout(sendMail, eta_ms);
From the docs:
These functions work just like their native JavaScript equivalents. If you call the native function, you'll get an error stating that Meteor code must always run within a Fiber, and advising to use Meteor.bindEnvironment
Meteor timers just bindEnvironment then delay the call as you wanted.

Meteor observeChanges removed callback won't execute server methods

I am observing changes on the Results collection on the client and calling methods on the server for the added and removed callbacks. (The following is only on the client and 'foo' is on the server.)
Results.find().observeChanges({
added: function (id, doc) {
console.log('added on client')
Meteor.call('foo')
},
removed: function (id) {
console.log('removed on client')
Meteor.call('foo')
}
})
Here is the server code.
Meteor.methods({
foo: function() {
console.log('server code run')
}
})
If I insert a document on the client I get 'added on client' on the client and 'server code run' on the server. If I remove a document on the client, I get 'removed on the client' on the client, but nothing on the server at all.
Does anyone know what is going on?
A few suggestions:
Does the code run on the server (e.g if you put it into a Tracker.autorun block)?
Are there any errors on the server console?
Is there any error on the browser console?
If other code within the removed callback gets executed, the server method call will be executed too. There are no restrictions for these callbacks. I don't think your problem is with the code you've pasted. Maybe add the server method code as well.

Meteor Streams : client doesn't receive streams

i'm working on a simple app based on meteor and MeteorStreams.
The aim is simple :
one user will click on a button to create a room
other users will join the room
those users can emit streams with simple message
the creator will listen to that message and then display them
In fact : message from other users are sent (log in server script), but the creator doesn't receive them.
If i reload the page of the creator, then it will get messages sent from other user.
I don't really understand why it doesn't work the first time.
I use meteor-router for my routing system.
Code can be seen here
https://github.com/Rebolon/MeetingTimeCost/tree/feature/pokerVoteProtection
for the client side code is availabel in client/views/poker/* and client/helpers
for the server stream's code is in server/pokerStreams.js
Application can be tested here : http://meetingtimecost.meteor.com
The creator must be logged.
If you have any idea, any help is welcome.
Thanks
Ok, Ok,
after doing some debugging, i now understand what is wrong in my code :
it's easy in fact. The problem comes from the fact that i forgot to bind the Stream.on event to Deps.autorun.
The result is that this part of code was not managed by reactivity so it was never re-run automatically when the Session changed.
The solution is so easy with Meteor : just wrap this part of code inside the Deps.autorun
Meteor.startup(function () {
Deps.autorun(function funcReloadStreamListeningOnNewRoom () {
PokerStream.on(Session.get('currentRoom') + ':currentRoom:vote', function (vote) {
var voteFound = 0;
// update is now allowed
if (Session.get('pokerVoteStatus') === 'voting') {
voteFound = Vote.find({subscriptionId: this.subscriptionId});
if (!voteFound.count()) {
Vote.insert({value: vote, userId: this.userId, subscriptionId: this.subscriptionId});
} else {
Vote.update({_id: voteFound._id}, {$set: {value: vote}});
}
}
});
});
});
So it was not a Meteor Streams problem, but only my fault.
Hope it will help people to understand that outside Template and Collection, you need to wrap your code inside Deps if you want reactivity.

How to call async method from Meteor own callbacks?

I've just spent a few hours reading SO with answers such as Meteor: Calling an asynchronous function inside a Meteor.method and returning the result
Unfortunately, I still didn't manage to user fibers, or futures for that matter.
I'm trying to do something fairly simple (I think!).
When creating a user, add a variable to the user object, based on the result of an asynchronous method. So imagine if you will my async method is called on a 3rd party db server called BANK, which could take several seconds to return.
Accounts.onCreateUser(function(options,user){
var Fiber = Npm.require("fibers");
Fiber(function() {
BANK.getBalance(function(err, theBalance) {
if (err) return console.log(err);
_.extend(user,{
balance: theBalance;
});
});
}).run();
return user;
});
So what happens in the above is that the BANK method is called, but by the time it returns the code has already moved on and _.extend is never invoked.
I tried placing the return call inside the Fiber, that only made things worse: it never return user. Well it did, but 3 seconds too late so by then everything downstream was bailing out.
Thank you for any help!
Answering my own question which hopefully will help some people in the future. This is based on the excellent advice of Avital Oliver and David Glasser to have a look at Mike Bannister's meteor-async.md. You can read it here: https://gist.github.com/possibilities/3443021
Accounts.onCreateUser(function(options,user){
_.extend(user,{
balance: getBalance(),
});
return user;
});
function getBalance() {
var Future = Npm.require("fibers/future");
var fut = new Future();
BANK.getBalance(function(err, bal) {
if (err) return console.log(err);
fut.return(bal);
});
return fut.wait();
}
I believe there's an even better way to handle this, which is directly by wrapping the BANK API in Futures within the npm package itself, as per this example (from Avital Oliver): https://github.com/avital/meteor-xml2js-npm-demo/blob/master/xml2js-demo.js
I hope it helps!
Use this.unblock() on server side code.
From Meteor 1.0 documentation: "Allow subsequent method from this client to begin running in a new fiber.On the server, methods from a given client run one at a time. The N+1th invocation from a client won't start until the Nth invocation returns. However, you can change this by calling this.unblock. This will allow the N+1th invocation to start running in a new fiber."
Meteor.methods({checkTwitter: function (userId) {
check(userId, String);
this.unblock();
try {
var result = HTTP.call("GET", "http://api.twitter.com/xyz",
{params: {user: userId}});
return true;
} catch (e) {
// Got a network error, time-out or HTTP error in the 400 or 500 range.
return false;
}
}});
method calls use the sync style (see 'sync call' here http://docs.meteor.com/#meteor_call) on the server side, which is where this create user method runs - you should be able to do something like
Accounts.onCreateUser(function(options, user) {
user.balance = Meteor.call('getBankBalance', params);
return user;
});
Thanks yo so much that's work, This solution its better for Meteor projects, because Fibers module installed by default. mrt add npm has a method for this too -> Meteor.sync . For any nodeJS projects there is a other module based on Fibers, its name is Fibrous
Reference:https://github.com/goodeggs/fibrous

Resources