node-neo4j icon indicating copy to clipboard operation
node-neo4j copied to clipboard

Auto-retry transient errors

Open aseemk opened this issue 10 years ago • 3 comments

With Neo4j v2's new error classifications, we now know which errors are transient and will likely go away with a simple retry:

http://neo4j.com/docs/stable/status-codes.html

We could/should implement (configurable) auto-retry for queries that hit transient errors.

https://groups.google.com/d/topic/neo4j-ecosystem/1apg9CK34e4/discussion

Aspects to consider/implement:

  • [ ] Option to configure how many times to auto-retry, if any. Default to 2?
  • [ ] Callback when a retry is happening, so the app can e.g. log a warning if it likes?
  • [ ] Any delay or backoff between retries? Exponential backoff feels like overkill for only a couple of retries, but might still be wise?

aseemk avatar Feb 18 '15 15:02 aseemk

An open issue here is that transactions seem to never ultimately commit if a TransientError is encountered within them. Asking the Neo team about this, but punting til that's resolved.

aseemk avatar Mar 02 '15 14:03 aseemk

An open issue here is that transactions seem to never ultimately commit if a TransientError is encountered within them. Asking the Neo team about this, but punting til that's resolved.

This behavior has been improved, and the docs fixed. Transactions now roll back right away in the case of any errors. Issue https://github.com/neo4j/neo4j/issues/5258; pull https://github.com/neo4j/neo4j/pull/5394.

aseemk avatar Oct 12 '15 17:10 aseemk

I currently handle this with the following wrapper code: where graphObj is my connection to neo4j Using a fixed 400ms retry with a maximum of 5 retries.

var cypher_wrapper = function(queryObj, callback){
  // some code omitted... defining graphObj and loggerObj
  // queryObj usually of the form { query:query, params:params }
  var async = require('async');
  var task = function (cb){
    graphObj.cypher(queryObj, function(err, result){
      if(err && err.name === "neo4j.TransientError"){
        cb(err, {'_err':err, '_result':result});
      } else {
        cb(null, {'_err':err, '_result':result});
      }
    });
  };
  async.retry({ times: 5, interval: 400 }, task.bind(this), function(err, result) {
    if (err) {
      loggerObj.error(err);
    }
    callback(result._err, result._result);
  });
};

closedLoop avatar Nov 06 '15 13:11 closedLoop