Que se passe-t-il avec Meteor et Fibres / bindEnvironment ()?

J’ai des difficultés à utiliser Fibers / Meteor.bindEnvironment (). J’ai essayé de mettre à jour le code et de l’insérer dans une collection si la collection commence vide. Tout cela est censé fonctionner côté serveur au démarrage.

function insertRecords() { console.log("inserting..."); var client = Knox.createClient({ key: apikey, secret: secret, bucket: 'profile-testing' }); console.log("created client"); client.list({ prefix: 'projects' }, function(err, data) { if (err) { console.log("Error in insertRecords"); } for (var i = 0; i < data.Contents.length; i++) { console.log(data.Contents[i].Key); if (data.Contents[i].Key.split('/').pop() == "") { Projects.insert({ name: data.Contents[i].Key, contents: [] }); } else if (data.Contents[i].Key.split('.').pop() == "jpg") { Projects.update( { name: data.Contents[i].Key.substr(0, data.Contents[i].Key.lastIndexOf('.')) }, { $push: {contents: data.Contents[i].Key}} ); } else { console.log(data.Contents[i].Key.split('.').pop()); } } }); } if (Meteor.isServer) { Meteor.startup(function () { if (Projects.find().count() === 0) { boundInsert = Meteor.bindEnvironment(insertRecords, function(err) { if (err) { console.log("error binding?"); console.log(err); } }); boundInsert(); } }); } 

La première fois que j’écrivais cela, j’ai eu des erreurs et j’avais besoin d’envelopper mes rappels dans un bloc Fiber (), puis lors d’une discussion sur IRC, une personne recommandant d’essayer Meteor.bindEnvironment () à la place, car cela devrait le mettre dans une fibre. Cela n’a pas fonctionné (la seule sortie que j’ai vue était l’ inserting... , ce qui signifie que bindEnvironment () n’a pas généré d’erreur, mais il n’a également exécuté aucun code à l’intérieur du bloc). Puis je suis arrivé à ça. Mon erreur est maintenant: Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment. Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.

Je suis nouveau sur Node et ne comprends pas complètement le concept de fibres. D’après ce que j’ai compris, ils sont analogues aux threads en C / C ++ / tous les langages avec threading, mais je ne comprends pas les implications qui s’étendent à mon code côté serveur / pourquoi mon code génère une erreur en essayant de l’insérer dans une collection. Quelqu’un peut-il m’expliquer cela?

Je vous remercie.

Vous utilisez bindEnvironment légèrement de manière incorrecte. Parce qu’il est déjà utilisé dans une fibre et que le rappel provenant du client Knox n’est plus dans une fibre.

Il y a deux cas d’utilisation de bindEnvironment (à laquelle je peux penser, il pourrait y en avoir plus!):

  • Vous avez une variable globale qui doit être modifiée mais vous ne voulez pas qu’elle affecte les sessions d’autres utilisateurs

  • Vous gérez un rappel en utilisant un module tiers api / npm (ce qui semble être le cas)

Meteor.bindEnvironment crée une nouvelle fibre et copie les variables et l’environnement de Fiber actuels dans la nouvelle fibre. Le point dont vous avez besoin est lorsque vous utilisez le rappel de méthode de votre module de nom.

Heureusement, il existe une alternative qui prend en charge le rappel qui vous attend et le lie dans une fibre appelée Meteor.wrapAsync .

Pour que vous puissiez faire ceci:

Votre fonction de démarrage possède déjà une fibre optique et aucun rappel, vous n’avez donc pas besoin de bindEnvironment ici.

 Meteor.startup(function () { if (Projects.find().count() === 0) { insertRecords(); } }); 

Et vos enregistrements d’insertion fonctionnent (avec wrapAsync) pour que vous n’ayez pas besoin de rappel

 function insertRecords() { console.log("inserting..."); var client = Knox.createClient({ key: apikey, secret: secret, bucket: 'profile-testing' }); client.listSync = Meteor.wrapAsync(client.list.bind(client)); console.log("created client"); try { var data = client.listSync({ prefix: 'projects' }); } catch(e) { console.log(e); } if(!data) return; for (var i = 1; i < data.Contents.length; i++) { console.log(data.Contents[i].Key); if (data.Contents[i].Key.split('/').pop() == "") { Projects.insert({ name: data.Contents[i].Key, contents: [] }); } else if (data.Contents[i].Key.split('.').pop() == "jpg") { Projects.update( { name: data.Contents[i].Key.substr(0, data.Contents[i].Key.lastIndexOf('.')) }, { $push: {contents: data.Contents[i].Key}} ); } else { console.log(data.Contents[i].Key.split('.').pop()); } } }); 

Quelques points à garder à l'esprit. Les fibres ne sont pas comme des fils. Il n'y a qu'un seul thread dans NodeJS.

Les fibres ressemblent davantage à des événements pouvant être exécutés en même temps, mais sans se bloquer s'il existe un scénario de type en attente (par exemple, le téléchargement d'un fichier depuis Internet).

Ainsi, vous pouvez avoir un code synchrone et ne pas bloquer les événements des autres utilisateurs. Ils s'exécutent à tour de rôle mais continuent de fonctionner dans un seul thread. C'est ainsi que Meteor a un code synchrone côté serveur, qui peut attendre des choses, mais les autres utilisateurs ne seront pas bloqués par cela et pourront faire des choses parce que leur code s'exécute dans une fibre différente.

Chris Mather a quelques bons articles à ce sujet sur http://eventedmind.com

Que fait Meteor.wrapAsync?

Meteor.wrapAsync prend la méthode que vous lui donnez comme premier paramètre et l'exécute dans la fibre actuelle.

Il y attache également un rappel (il suppose que la méthode prend un dernier paramètre qui a un rappel où le premier paramètre est une erreur et le second le résultat tel que function(err,result) .

Le rappel est lié à Meteor.bindEnvironment et bloque la fibre actuelle jusqu'à ce que le rappel soit déclenché. Dès que le rappel est déclenché, il renvoie le result ou renvoie l' err .

C'est donc très pratique pour convertir le code asynchrone en code synchrone car vous pouvez utiliser le résultat de la méthode sur la ligne suivante au lieu d'utiliser un rappel et imbriquer des fonctions plus profondes. Il s'occupe également de bindEnvironment pour vous afin que vous n'ayez pas à craindre de perdre la scope de votre fibre.

Mise à jour de Meteor._wrapAsync est maintenant Meteor.wrapAsync et documenté .