2012-04-17 12 views
38

Ho il seguente codice in server/statusboard.js;"Il codice Meteor deve sempre essere eseguito all'interno di una fibra" quando si chiama Collection.insert sul server

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); 
}); 

In pratica, sta recuperando alcuni dati da un feed JSON e sta provando a inserirlo in una raccolta.

Quando avvio Meteor ottengo la seguente eccezione;

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 

Non sono sicuro di cosa significhi quell'errore. Qualcuno ha qualche idea o può suggerire un approccio diverso?

+0

dovrei mettere in chiaro che "Servizi" è stato definito altrove in un file separato (comune sia al cliente e server). –

+0

Questa riga è il problema: 'Servizi.insert ({host: host, servizio: service, hardState: hardState, currState: currState}); ' Penso che sia perché è in un callback, non c'è modo di testare al momento per te. – jonathanKingston

+2

Meteor ora include una libreria di richieste HTTP che semplifica molto il tuo caso: http://docs.meteor.com/#meteor_http – debergalis

risposta

15

Come accennato in precedenza è perché il codice di esecuzione all'interno di un callback.

Qualsiasi codice in esecuzione sul lato server deve essere contenuto in una fibra.

provare a modificare le getServices funzione per assomigliare a questo:

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(); 
} 

Ho appena incontrato un problema simile e questo ha funzionato per me. Quello che devo dire però è che sono molto nuovo a questo e non so se è così che dovrebbe essere fatto.

Probabilmente si potrebbe farla franca solo avvolgendo l'istruzione di inserimento nella fibra, ma non sono positivo.

7

In base ai miei test, è necessario avvolgere l'inserto nel codice che ho provato che è simile all'esempio precedente.

Ad esempio, l'ho fatto e non è riuscito con errore 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(); 
    } 
} 

Ho fatto questo e ha funzionato bene senza errori.

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? 
     } 
    } 
); 
    } 
} 

Ho pensato che questo potrebbe aiutare gli altri incontrando questo problema. Non ho ancora provato a chiamare il tipo asynchy di servizio esterno dopo il codice interno e l'ho inserito in una fibra. Potrebbe valere la pena testarlo. Nel mio caso, avevo bisogno di sapere che l'azione remota è avvenuta prima che io faccia la mia azione locale.

Spero che questo contribuisca a questa domanda.

+0

[02:33:57] questa è una cattiva risposta, dovrei commentare su questo. [02:34:20] che crea una fibra, ma non imposta il contesto meteorico utile al suo interno e in realtà non blocca il metodo esterno sul thread interno. –

+2

@ TomWijsman che è preciso allora? Fibra attorno all'intero blocco di codice nel metodo? –

+1

[01:40:21] 1: sganciare il recinto di scrittura. vedere l'implementazione di Meteor.setTimeout in packages/meteor/timers.js per un esempio di questo. [01:41:19] 2: avvolgi qualsiasi callback definito in una nuova fibra, in modo che il metodo non ritorni fino all'esecuzione della richiamata. è così che vengono implementate le API sincere di meteor, come nei pacchetti/mongo-livedata/mongo_driver.js [01:42:02] la risposta giusta è in realtà 3: urlati contro di noi per non implementare una decente API sincrona per qualsiasi cosa tu stia provando da fare :) –

47

Il semplice avvolgimento della funzione in una fibra potrebbe non essere sufficiente e può comportare un comportamento imprevisto.

Il motivo è che, insieme a Fibre, Meteor richiede un set di variabili collegate a una fibra. Meteor utilizza i dati collegati a una fibra come ambito dinamico e il modo più semplice per utilizzarlo con 3rd party api è utilizzare 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'); })); 

guardare questi video in mente evented se volete saperne di più: https://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variables https://www.eventedmind.com/posts/meteor-what-is-meteor-bindenvironment

+1

Questo ha fatto il trucco per me. La risposta accettata non ha funzionato, perché 'Fiber' non esiste! –

+1

Le fibre esistono solo sul lato server, lo hai messo in comune o codice client? – Thomas

+1

Questa dovrebbe essere la risposta accettata –

Problemi correlati