2012-05-30 19 views
5

Estoy trabajando en un servicio simple usando Node.js. Recibe los archivos cargados, los almacena en el disco y registra algunos metadatos en una tabla de Oracle. Estoy usando el paquete db-oracle junto con la agrupación de conexiones, siguiendo este artículo: http://nodejsdb.org/2011/05/connection-pooling-node-db-with-generic-pool/db-oracle no está lavando datos

Sin embargo, he notado que los datos que inserto solo se envían a la base de datos Oracle después de que el grupo de conexiones cierra la conexión inactiva, llamando su método disconnect().

¿Hay alguna forma de purgar los datos antes de enviar la señal 'OK' a mi cliente? La forma en que está funcionando ahora, un bloqueo en mi servicio web o en Oracle mismo puede causar la pérdida de datos, y el cliente de mi servicio no lo sabría. De hecho, probé esto al matar el proceso de mi aplicación después de algunas cargas y, de hecho, los datos se perdieron.

Aquí hay una versión simplificada del código:

var express = require('express'); 
var app = module.exports = express.createServer(); 

app.post('/upload', handleUpload); 

app.listen(4001, function(){ 
    console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); 
}); 

function handleUpload(req, res) { 
    res.contentType('application/xml'); 

    var buf = ''; 
    req.on('data', function(chunk) { buf += chunk; }); 
    req.on('end', function() { 
    saveUpload(req, res, buf); 
    }); 
} 

function saveUpload(req, res, buf) { 
    if (buf.length == 0) 
    return sendError(res, 'No data supplied', 422); 

    var payload = new Buffer(buf, 'base64'); 

    files.save(payload, function(err, savedFile) { 
    if (err) 
     return sendError(res, 'Error while saving', 500); 

    var obj = { ip: req.connection.remoteAddress, location: savedFile.path, 
       created_at: new Date(), updated_at: new Date() }; 

    var fields = ['IP', 'LOCATION', 'CREATED_AT', 'UPDATED_AT']; 
    var values = fields.map(function(v) { return obj[v.toLowerCase()] }); 

    pool.acquire(function(err, conn) { 
     if (err) 
     return sendError(res, err, 500); 

     var q = conn.query().insert('FILES', fields, values); 

     q.execute(function(err, result) { 
     pool.release(conn); 

     if (err) 
      return sendError(res, err, 500); 

     if (result.affected < 1) 
      return sendError(res, 'Error saving the record', 500); 

     // The next statement sends the final result to the client. 
     // However, the new record was not yet flushed to the database. 
     res.end('<ok />'); 
     }); 
    }); 
    }); 
} 

function sendError(res, err, code) { 
    console.log(err); 
    res.send('<error>' + err + '</error>', code || 500); 
} 

Como solución, he tratado de poner en práctica un conjunto de conexiones falso y liberar todas las conexiones adquiridas, pero ahora mi aplicación está muriendo con el mensaje: pure virtual method calledAbort trap: 6

Aquí está la agrupación de conexiones falsa:

var fakePool = { 
    acquire: function(callback) { 
    new oracle.Database(config.database).connect(function(err, server) { 
     callback(err, this); 
    }); 
    }, 
    release: function(conn) { 
    conn.disconnect(); 
    } 
}; 

para que quede claro, no me importa el pooler falsa conexión, que era sólo una solución sucia Quiero poder vaciar los datos a Oracle antes de enviando el 'OK' a mi cliente.

Por cierto que también se abrió un billete en su Github: https://github.com/mariano/node-db-oracle/issues/38

+0

No veo ningún commit en el código ... –

+0

Sí, los paquetes 'db-oracle' y' node-db' no exponen ninguno, AFAIK. He profundizado en su documentación y fuentes y no he encontrado ninguna manera de realizar explícitamente una confirmación. Sin embargo, he encontrado un método 'commit' en los documentos OCCI. ¿Tal vez tendré que bifurcar el proyecto y exponer el método de compromiso? –

+0

¿Estos paquetes quizás dependan del comportamiento de confirmación automática (ugh!)? –

Respuesta

6

Obviamente, falta un compromiso de transacción.

node-db no necesita exponer una API de confirmación porque en la mayoría de los RDBMS (incluido Oracle), COMMIT es una consulta válida. Dado que el paquete permite la ejecución de consultas arbitrarias, commit/rollback se supone que debe hacerse mediante un simple ejecutar()

El código debe cambiarse de la siguiente manera:

pool.acquire(function(err, conn) { 
    if (err) 
    return sendError(res, err, 500); 

    var q = conn.query().insert('FILES', fields, values); 
    q.execute(function(err, result) { 

    if (err || result.affected < 1) { 
     pool.release(conn); 
     return sendError(res, err, 500); 
    } 

    conn.query().execute("commit", function(err,result) { 
     if (err) { 
     pool.release(conn); 
     return sendError(res, err, 500); 
     } 
     res.end('<ok />'); 
     pool.release(conn); 
    }); 
    }); 
}); 
+0

¡Lo intentaré, gracias! –

1

Ésta no es una respuesta exacta a su pregunta, pero echar un vistazo a node-oracle paquete. Carece de agrupamiento de conexiones, pero su funcionalidad commit/rollback se puede controlar al menos desde el código. Y siempre puedes mezclarlo con un generic pool solution such as node-pool.

+0

Gracias, @ npe ... También intentaré 'node-oracle'. Lo triste es que no está integrado con 'node-db'. –

Cuestiones relacionadas