From 41eec4740f9fc68190690e5fac071f8ea089b850 Mon Sep 17 00:00:00 2001 From: Stephen Sawchuk Date: Mon, 13 Jun 2016 10:26:59 -0400 Subject: [PATCH] datastore: automatically rollback a transaction --- lib/datastore/transaction.js | 43 ++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js index d78da8b043d0..8b56393839ac 100644 --- a/lib/datastore/transaction.js +++ b/lib/datastore/transaction.js @@ -102,8 +102,12 @@ nodeutil.inherits(Transaction, DatastoreRequest); /** * Commit the remote transaction and finalize the current transaction instance. * + * If the commit request fails, we will automatically rollback the transaction. + * * @param {function} callback - The callback function. * @param {?error} callback.err - An error returned while making this request. + * If the commit fails, we automatically try to rollback the transaction (see + * {module:datastore/transaction#rollback}). * @param {object} callback.apiResponse - The full API response. * * @example @@ -114,7 +118,7 @@ nodeutil.inherits(Transaction, DatastoreRequest); * }); */ Transaction.prototype.commit = function(callback) { - var that = this; + var self = this; callback = callback || util.noop; @@ -179,7 +183,7 @@ Transaction.prototype.commit = function(callback) { var method = modifiedEntity.method; var args = modifiedEntity.args.reverse(); - DatastoreRequest.prototype[method].call(that, args, util.noop); + DatastoreRequest.prototype[method].call(self, args, util.noop); }); var protoOpts = { @@ -195,14 +199,29 @@ Transaction.prototype.commit = function(callback) { this.request_(protoOpts, reqOpts, function(err, resp) { if (err) { - callback(err, resp); + // Rollback automatically for the user. + self.rollback(function(err) { + if (err) { + err.message = [ + 'The commit was not successful and the transaction could not be', + 'rolled back. You may want to try calling transaction.rollback().', + '\n', + '\n', + err.message + ].join(''); + } + + // Provide the response items from the failed commit to the user. A + // successful rollback should be transparent. + callback(err, resp); + }); return; } // The `callbacks` array was built previously. These are the callbacks that // handle the API response normally when using the DatastoreRequest.save and // .delete methods. - that.requestCallbacks_.forEach(function(cb) { + self.requestCallbacks_.forEach(function(cb) { cb(null, resp); }); @@ -277,10 +296,10 @@ Transaction.prototype.createQuery = function() { * }); */ Transaction.prototype.delete = function(entities) { - var that = this; + var self = this; arrify(entities).forEach(function(ent) { - that.modifiedEntities_.push({ + self.modifiedEntities_.push({ entity: { key: ent }, @@ -311,7 +330,7 @@ Transaction.prototype.delete = function(entities) { * }); */ Transaction.prototype.rollback = function(callback) { - var that = this; + var self = this; callback = callback || util.noop; @@ -321,7 +340,7 @@ Transaction.prototype.rollback = function(callback) { }; this.request_(protoOpts, {}, function(err, resp) { - that.skipCommit = true; + self.skipCommit = true; callback(err || null, resp); }); @@ -358,7 +377,7 @@ Transaction.prototype.rollback = function(callback) { * }); */ Transaction.prototype.run = function(callback) { - var that = this; + var self = this; callback = callback || util.noop; @@ -373,7 +392,7 @@ Transaction.prototype.run = function(callback) { return; } - that.id = resp.transaction; + self.id = resp.transaction; callback(null, resp); }); @@ -491,10 +510,10 @@ Transaction.prototype.run = function(callback) { * }); */ Transaction.prototype.save = function(entities) { - var that = this; + var self = this; arrify(entities).forEach(function(ent) { - that.modifiedEntities_.push({ + self.modifiedEntities_.push({ entity: { key: ent.key },