Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Update waiter implementation for new config format

  • Loading branch information...
commit 255b8c45c8fdb1a32adf3c62fc88c0023a1ca2f3 1 parent b49e872
@lsegal lsegal authored
Showing with 110 additions and 46 deletions.
  1. +92 −41 lib/resource_waiter.js
  2. +18 −5 lib/service.js
View
133 lib/resource_waiter.js
@@ -20,6 +20,15 @@ var inherit = AWS.util.inherit;
* @api private
*/
AWS.ResourceWaiter = inherit({
+ /**
+ * Waits for a given state on a service object
+ * @param service [Service] the service object to wait on
+ * @param state [String] the state (defined in waiter configuration) to wait
+ * for.
+ * @example Create a waiter for running EC2 instances
+ * var ec2 = new AWS.EC2;
+ * var waiter = new AWS.ResourceWaiter(ec2, 'instanceRunning');
+ */
constructor: function constructor(service, state) {
this.service = service;
this.state = state;
@@ -33,7 +42,7 @@ AWS.ResourceWaiter = inherit({
this.loadWaiterConfig(this.state);
if (!this.expectedValue) {
- this.expectedValue = this.config.dataValue;
+ this.expectedValue = this.config.successValue;
}
},
@@ -66,65 +75,98 @@ AWS.ResourceWaiter = inherit({
var retryDelay = request.retryDelay;
request.retryDelay = function(resp) {
if (resp.error.code === 'ResourceNotReady') {
- return waiter.config.delay * 1000;
+ return waiter.config.interval * 1000;
} else {
- return retryDelay(resp);
+ return retryDelay.call(request, resp);
}
};
- request.removeAllListeners('extractError');
- request.on('extractData', function (resp) {
- if (!waiter.handlers.checkSuccess(waiter, resp)) {
- resp.data = null;
- resp.error = AWS.util.error(new Error(), {
- code: 'ResourceNotReady',
- message: 'Resource is not in the state ' + waiter.state,
- originalError: resp.error,
- retryable: true
- });
- }
- });
+ request.removeListener('extractError', AWS.EventListeners.Core.SETUP_ERROR);
+ if (waiter.config.successType === 'error') {
+ request.on('extractError', function (resp) {
+ var success = waiter.checkError(waiter, resp);
+ if (!success) {
+ resp.data = null;
+ resp.error = AWS.util.error(new Error(), {
+ code: 'ResourceNotReady',
+ message: 'Resource is not in the state ' + waiter.state,
+ originalError: resp.error,
+ retryable: success === null ? false : true
+ });
+ } else {
+ resp.error = null;
+ }
+ });
+ } else {
+ request.removeAllListeners('extractError');
+ request.on('extractData', function (resp) {
+ var success = waiter.checkSuccess(waiter, resp);
+ if (!success) {
+ resp.data = null;
+ resp.error = AWS.util.error(new Error(), {
+ code: 'ResourceNotReady',
+ message: 'Resource is not in the state ' + waiter.state,
+ originalError: resp.error,
+ retryable: success === null ? false : true
+ });
+ }
+ });
+ }
var retryCheck = AWS.EventListeners.Core.RETRY_CHECK;
var index = request._events['retry'].indexOf(retryCheck);
request._events['retry'][index] = function newRetryCheck(resp) {
+ var e = resp.error;
resp.waiterRetryCount = resp.waiterRetryCount || 0;
- if (resp.error && resp.error.code === 'ResourceNotReady') {
- if (resp.waiterRetryCount < waiter.config.maxRetries) {
+ if (e && e.retryable && e.code === 'ResourceNotReady') {
+ if (resp.waiterRetryCount < waiter.config.maxAttempts) {
resp.waiterRetryCount++;
} else {
- throw resp.error;
+ throw e;
}
} else {
- retryCheck(resp);
+ retryCheck.call(resp.request, resp);
}
};
},
- handlers: {
- data: function dataStateHandler(waiter, resp) {
- if (!waiter.config.dataPath) return false;
- if (waiter.config.dataPath === '*' && resp.data) return true;
- var result = AWS.util.jamespath.find(waiter.config.dataPath, resp.data);
- if (waiter.expectedValue) return result === waiter.expectedValue;
- else return result ? true : false;
- },
-
- error: function errorStateHandler(waiter, resp) {
- return resp.error && resp.error.code === waiter.config.errorCode;
- },
-
- statusCode: function statusCodeStateHandler(waiter, resp) {
- return resp.httpResponse.statusCode === waiter.config.statusCode;
- },
-
- checkSuccess: function checkSuccess(waiter, resp) {
- return waiter.handlers.statusCode(waiter, resp) ||
- waiter.handlers.error(waiter, resp) ||
- waiter.handlers.data(waiter, resp);
+ /**
+ * Checks if the terminal expected success state has been met
+ * @return [Boolean]
+ */
+ checkSuccess: function checkSuccess(waiter, resp) {
+ if (!waiter.config.successPath) {
+ return resp.httpResponse.statusCode < 300;
}
+
+ var r = AWS.util.jamespath.find(waiter.config.successPath, resp.data);
+
+ if (waiter.config.failureValue &&
+ waiter.config.failureValue.indexOf(r) >= 0) {
+ return null; // fast fail
+ }
+
+ if (waiter.expectedValue) {
+ return r === waiter.expectedValue;
+ } else {
+ return r ? true : false;
+ }
+ },
+
+ /**
+ * Checks if the terminal expected error state has been met
+ * @return [Boolean]
+ */
+ checkError: function checkError(waiter, resp) {
+ return resp.httpResponse.statusCode === waiter.config.successValue;
},
+ /**
+ * Loads waiter configuration from API configuration and deals with inherited
+ * properties.
+ *
+ * @api private
+ */
loadWaiterConfig: function loadWaiterConfig(state, noException) {
if (!this.service.api.waiters[state]) {
if (noException) return;
@@ -140,6 +182,15 @@ AWS.ResourceWaiter = inherit({
this.loadWaiterConfig(superState, true);
}
- AWS.util.update(this.config, this.service.api.waiters[state]);
+ var config = this.config;
+ AWS.util.update(config, this.service.api.waiters[state]);
+
+ // inherit acceptor data
+ config.successType = config.successType || config.acceptorType;
+ config.successPath = config.successPath || config.acceptorPath;
+ config.successValue = config.successValue || config.acceptorValue;
+ config.failureType = config.failureType || config.acceptorType;
+ config.failurePath = config.failurePath || config.acceptorPath;
+ config.failureValue = config.failureValue || config.acceptorValue;
}
});
View
23 lib/service.js
@@ -157,11 +157,6 @@ AWS.Service = inherit({
return request;
},
- waitFor: function waitFor(state, params, callback) {
- var waiter = new AWS.ResourceWaiter(this, state);
- return waiter.wait(params, callback);
- },
-
/**
* Calls an operation on a service with the given input parameters, without
* any authentication data. This method is useful for "public" API operations.
@@ -201,6 +196,24 @@ AWS.Service = inherit({
},
/**
+ * Waits for a given state
+ *
+ * @param state [String] the state on the service to wait for
+ * @param params [map] a map of parameters to pass with each request
+ * @callback callback function(err, data)
+ * If a callback is supplied, it is called when a response is returned
+ * from the service.
+ * @param err [Error] the error object returned from the request.
+ * Set to `null` if the request is successful.
+ * @param data [Object] the de-serialized data returned from
+ * the request. Set to `null` if a request error occurs.
+ */
+ waitFor: function waitFor(state, params, callback) {
+ var waiter = new AWS.ResourceWaiter(this, state);
+ return waiter.wait(params, callback);
+ },
+
+ /**
* @api private
*/
addAllRequestListeners: function addAllRequestListeners(request) {
Please sign in to comment.
Something went wrong with that request. Please try again.