2012-04-17 8 views
38

Tengo el siguiente código en server/statusboard.js;"El código de meteorito siempre debe ejecutarse dentro de una Fiber" al llamar a Collection.insert en el servidor

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

Básicamente, está extrayendo algunos datos de una fuente JSON e intentando insertarlos en una colección.

Cuando inicio Meteor obtengo la siguiente excepción;

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 

No estoy seguro de lo que significa ese error. ¿Alguien tiene alguna idea o puede sugerir un enfoque diferente?

+0

vez debería dejar claro que "Servicios" se ha definido en otro lugar en un archivo separado (común tanto para el cliente y servidor). –

+0

Esta es la cuestión: 'Servicios.insert ({host: host, servicio: servicio, hardState: hardState, currState: currState}); ' Creo que es porque se trata de una devolución de llamada, no hay forma de probarlo en este momento. – jonathanKingston

+2

Meteor ahora incluye una biblioteca de solicitud HTTP que hace que su caso sea mucho más fácil: http://docs.meteor.com/#meteor_http – debergalis

Respuesta

15

Como se mencionó anteriormente es porque su código de ejecución dentro de una devolución de llamada.

Cualquier código que esté ejecutando en el lado del servidor debe estar dentro de una Fiber.

trate de cambiar su getServices funcionar a tener este aspecto:

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

Me acabo de encontrar con un problema similar y esto funcionó para mí. Lo que tengo que decir es que soy muy nuevo en esto y no sé si así es como debe hacerse esto.

Es probable que pueda salirse con la única envoltura de su declaración de inserción en la fibra, pero no estoy seguro.

7

Según mis pruebas, debe envolver la inserción en el código que probé, que es similar al ejemplo anterior.

Por ejemplo, lo hice y todavía falló con el error Fibras.

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

Lo hice y funcionó bien, sin errores.

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

Pensé que esto podría ayudar a otros a encontrar este problema. Todavía no he probado llamar al tipo de servicio externo asynchy después del código interno y envolverlo en un Fiber. Eso también valdría la pena probarlo. En mi caso, necesitaba saber la acción remota que sucedió antes de realizar mi acción local.

Espero que esto contribuya a este hilo de preguntas.

+0

[02:33:57] esa es una mala respuesta, debería comentar sobre eso. [02:34:20] que crea una Fibra, pero no configura el contexto meteorito útil dentro de ella, y en realidad no bloquea el método externo en el hilo interno. –

+2

@TomWijsman que es exacto entonces? Fibra alrededor de todo el bloque de código en el método? –

+1

[01:40:21] 1: desenganche la guía de escritura. ver la implementación de Meteor.setTimeout en packages/meteor/timers.js para ver un ejemplo de esto. [01:41:19] 2: envuelva cualquier devolución de llamada que haya definido en una nueva fibra, para que el método no vuelva hasta que se ejecute la devolución de llamada. así es como las API meteorológicas sincrónicas se implementan, como en los paquetes/mongo-livedata/mongo_driver.js [01:42:02] la respuesta correcta es en realidad 3: grítanos por no implementar una API síncrona decente para lo que sea que intentes hacer :) –

47

Simplemente envolviendo su función en una fibra podría no ser suficiente y puede conducir a un comportamiento inesperado.

La razón es que, junto con Fiber, Meteor requiere un conjunto de variables asociadas a una fibra. Meteor utiliza los datos adjuntos a una fibra como un alcance dinámico y la forma más fácil de usarlo con una API de terceros es usar 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'); })); 

ver estos videos en mente evented si usted quiere saber más: https://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variables https://www.eventedmind.com/posts/meteor-what-is-meteor-bindenvironment

+1

? Esto me sirvió de algo. La respuesta aceptada no funcionó, porque 'Fiber' no existe. –

+1

Las fibras solo existen en el lado del servidor, ¿lo puse en común o en el código del lado del cliente? – Thomas

+1

Esta debería ser la respuesta aceptada –

Cuestiones relacionadas