Skip to content

Commit

Permalink
fix async patch and post run
Browse files Browse the repository at this point in the history
  • Loading branch information
Qinyuan Wan committed Mar 22, 2016
1 parent 081e7f6 commit f058543
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 138 deletions.
201 changes: 92 additions & 109 deletions ClientRuntimes/NodeJS/ms-rest-azure/lib/azureServiceClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ function AzureServiceClient(credentials, options) {
if (!credentials) {
throw new Error('Azure clients require credentials.');
}

AzureServiceClient['super_'].call(this, credentials, options);

this.acceptLanguage = 'en-US';
this.generateClientRequestId = true;
this.longRunningOperationRetryTimeout = 30;

if (!options) options = {};

if (options.acceptLanguage !== null && options.acceptLanguage !== undefined) {
this.acceptLanguage = options.acceptLanguage;
}
Expand All @@ -62,68 +62,73 @@ util.inherits(AzureServiceClient, msRest.ServiceClient);
* @param {object} [options]
* @param {object} [options.customHeaders] headers that will be added to request
*/
AzureServiceClient.prototype.getPutOrPatchOperationResult = function (resultOfInitialRequest, options, callback) {
AzureServiceClient.prototype.getPutOrPatchOperationResult = function(resultOfInitialRequest, options, callback) {
var self = this;

if(!callback && typeof options === 'function') {
if (!callback && typeof options === 'function') {
callback = options;
options = null;
}
if (!callback) {
throw new Error('Missing callback');
}

if (!resultOfInitialRequest) {
return callback(new Error('Missing resultOfInitialRequest parameter'));
}


if (!resultOfInitialRequest.response) {
return callback(new Error('Missing resultOfInitialRequest.response'));
}

if (resultOfInitialRequest.response.statusCode !== 200 &&
resultOfInitialRequest.response.statusCode !== 201 &&
resultOfInitialRequest.response.statusCode !== 202) {
return callback(new Error(util.format('Unexpected polling status code from long running operation \'%s\'',
resultOfInitialRequest.response.statusCode !== 201 &&
resultOfInitialRequest.response.statusCode !== 202 &&
resultOfInitialRequest.response.statusCode !== 204) {
return callback(new Error(util.format('Unexpected polling status code from long running operation \'%s\'',
resultOfInitialRequest.response.statusCode)));
}

var pollingState = null;
try {
pollingState = new PollingState(resultOfInitialRequest, this.longRunningOperationRetryTimeout);
} catch (error) {
callback(error);
}

var resourceUrl = resultOfInitialRequest.request.url;
this._options = options;

async.whilst(
//while condition
function () {
var finished = [LroStates.Succeeded, LroStates.Failed, LroStates.Canceled].some(function (e) {
return pollingState.status === e;
function() {
var finished = [LroStates.Succeeded, LroStates.Failed, LroStates.Canceled].some(function(e) {
return e === pollingState.status;
});
return !finished;
},
//while loop body
function (callback) {
setTimeout(function () {
function(callback) {
setTimeout(function() {
if (pollingState.azureAsyncOperationHeaderLink) {
self._updateStateFromAzureAsyncOperationHeader(pollingState, false, function (err) {
self._updateStateFromAzureAsyncOperationHeader(pollingState, true, function(err) {
return callback(err);
});
} else if (pollingState.locationHeaderLink) {
self._updateStateFromLocationHeaderOnPut(pollingState, function (err) {
self._updateStateFromLocationHeader(pollingState, function(err) {
return callback(err);
});
} else {
self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function (err) {
} else if (resultOfInitialRequest.request.method === "PUT") {
self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function(err) {
return callback(err);
});
} else {
return callback(new Error('Location header is missing from long running operation.'));
}
}, pollingState.getTimeout());
},
//when done
function (err) {
function(err) {
if (pollingState.status === LroStates.Succeeded) {
if (!pollingState.resource) {
self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function (err) {
if ((pollingState.azureAsyncOperationHeaderLink || !pollingState.resource) && resultOfInitialRequest.request.method !== "DELETE" && resultOfInitialRequest.request.method !== "POST") {
self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function(err) {
return callback(err, pollingState.getOperationResponse());
});
} else {
Expand All @@ -142,65 +147,79 @@ AzureServiceClient.prototype.getPutOrPatchOperationResult = function (resultOfIn
* @param {object} [options]
* @param {object} [options.customHeaders] headers that will be added to request
*/
AzureServiceClient.prototype.getPostOrDeleteOperationResult = function (resultOfInitialRequest, options, callback) {
AzureServiceClient.prototype.getPostOrDeleteOperationResult = function(resultOfInitialRequest, options, callback) {
var self = this;

if (!callback && typeof options === 'function') {
callback = options;
options = null;
}
if (!callback) {
throw new Error('Missing callback');
}

if (!resultOfInitialRequest) {
return callback(new Error('Missing resultOfInitialRequest parameter'));
}

if (!resultOfInitialRequest.response) {
return callback(new Error('Missing resultOfInitialRequest.response'));
}

if (resultOfInitialRequest.response.statusCode !== 200 &&
resultOfInitialRequest.response.statusCode !== 202 &&
resultOfInitialRequest.response.statusCode !== 204) {
return callback(new Error(util.format('Unexpected polling status code from long running operation \'%s\'',
resultOfInitialRequest.response.statusCode !== 201 &&
resultOfInitialRequest.response.statusCode !== 202 &&
resultOfInitialRequest.response.statusCode !== 204) {
return callback(new Error(util.format('Unexpected polling status code from long running operation \'%s\'',
resultOfInitialRequest.response.statusCode)));
}

var pollingState = null;
try {
pollingState = new PollingState(resultOfInitialRequest, this.longRunningOperationRetryTimeout);
} catch (error) {
callback(error);
}

var resourceUrl = resultOfInitialRequest.request.url;
this._options = options;

async.whilst(
function () {
var finished = [LroStates.Succeeded, LroStates.Failed, LroStates.Canceled].some(function (e) {
function() {
var finished = [LroStates.Succeeded, LroStates.Failed, LroStates.Canceled].some(function(e) {
return e === pollingState.status;
});
return !finished;
},
function (callback) {
setTimeout(function () {
function(callback) {
setTimeout(function() {
if (pollingState.azureAsyncOperationHeaderLink) {
self._updateStateFromAzureAsyncOperationHeader(pollingState, true, function (err) {
self._updateStateFromAzureAsyncOperationHeader(pollingState, true, function(err) {
return callback(err);
});
} else if (pollingState.locationHeaderLink) {
self._updateStateFromLocationHeaderOnPostOrDelete(pollingState, function (err) {
self._updateStateFromLocationHeader(pollingState, function(err) {
return callback(err);
});
} else if (resultOfInitialRequest.request.method === "PUT") {
self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function(err) {
return callback(err);
});
} else {
return callback(new Error('Location header is missing from long running operation.'));
}
}, pollingState.getTimeout());
},
function (err) {
if (pollingState.status === LroStates.Succeeded ) {
return callback(null, pollingState.getOperationResponse());
//when done
function(err) {
if (pollingState.status === LroStates.Succeeded) {
if ((pollingState.azureAsyncOperationHeaderLink || !pollingState.resource) && resultOfInitialRequest.request.method !== "DELETE" && resultOfInitialRequest.request.method !== "POST") {
self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function(err) {
return callback(err, pollingState.getOperationResponse());
});
} else {
return callback(null, pollingState.getOperationResponse());
}
} else {
return callback(pollingState.getCloudError(err));
}
Expand All @@ -212,14 +231,14 @@ AzureServiceClient.prototype.getPostOrDeleteOperationResult = function (resultOf
* @param {object} [pollingState] - The object to persist current operation state.
* @param {boolean} [inPostOrDelete] - Invoked by Post Or Delete operation.
*/
AzureServiceClient.prototype._updateStateFromAzureAsyncOperationHeader = function (pollingState, inPostOrDelete, callback) {
this._getStatus(pollingState.azureAsyncOperationHeaderLink, function (err, result) {
AzureServiceClient.prototype._updateStateFromAzureAsyncOperationHeader = function(pollingState, inPostOrDelete, callback) {
this._getStatus(pollingState.azureAsyncOperationHeaderLink, function(err, result) {
if (err) return callback(err);

if (!result.body || !result.body.status) {
return callback(new Error('The response from long running operation does not contain a body.'));
}

pollingState.status = result.body.status;
pollingState.error = result.body.error;
pollingState.response = result.response;
Expand All @@ -233,36 +252,25 @@ AzureServiceClient.prototype._updateStateFromAzureAsyncOperationHeader = functio
};

/**
* Retrieve PUT operation status by polling from 'location' header.
* Retrieve PUT/POST/PATCH/DELETE operation status by polling from 'location' header.
* @param {object} [pollingState] - The object to persist current operation state.
*/
AzureServiceClient.prototype._updateStateFromLocationHeaderOnPut = function (pollingState, callback) {
this._getStatus(pollingState.locationHeaderLink, function (err, result) {
AzureServiceClient.prototype._updateStateFromLocationHeader = function(pollingState, callback) {
this._getStatus(pollingState.locationHeaderLink, function(err, result) {
if (err) return callback(err);

pollingState.updateResponse(result.response);
pollingState.request = result.request;

var statusCode = result.response.statusCode;
if (statusCode === 202) {
pollingState.status = LroStates.InProgress;
}
else if (statusCode === 200 ||
statusCode === 201) {

if (!result.body) {
return callback(new Error('The response from long running operation does not contain a body.'));
}

// In 202 pattern on PUT ProvisioningState may not be present in
// the response. In that case the assumption is the status is Succeeded.
if (result.body.properties && result.body.properties.provisioningState) {
pollingState.status = result.body.properties.provisioningState;
}
else {
pollingState.status = LroStates.Succeeded;
}

} else if (statusCode === 200 ||
statusCode === 201 ||
statusCode === 204) {

pollingState.status = LroStates.Succeeded;

pollingState.error = {
code: pollingState.Status,
message: util.format('Long running operation failed with status \'%s\'.', pollingState.status)
Expand All @@ -273,59 +281,34 @@ AzureServiceClient.prototype._updateStateFromLocationHeaderOnPut = function (pol
});
};

/**
* Retrieve POST or DELETE operation status by polling from 'location' header.
* @param {object} [pollingState] - The object to persist current operation state.
*/
AzureServiceClient.prototype._updateStateFromLocationHeaderOnPostOrDelete = function (pollingState, callback) {
this._getStatus(pollingState.locationHeaderLink, function (err, result) {
if (err) return callback(err);

pollingState.updateResponse(result.response);
pollingState.request = result.request;

var statusCode = result.response.statusCode;
if (statusCode === 202) {
pollingState.status = LroStates.InProgress;
}
else if (statusCode === 200 ||
statusCode === 201 ||
statusCode === 204) {
pollingState.status = LroStates.Succeeded;
pollingState.resource = result.body;
}
callback(null);
});
};

/**
* Polling for resource status.
* @param {function} [resourceUrl] - The url of resource.
* @param {object} [pollingState] - The object to persist current operation state.
*/
AzureServiceClient.prototype._updateStateFromGetResourceOperation = function (resourceUrl, pollingState, callback) {
this._getStatus(resourceUrl, function (err, result) {
AzureServiceClient.prototype._updateStateFromGetResourceOperation = function(resourceUrl, pollingState, callback) {
this._getStatus(resourceUrl, function(err, result) {
if (err) return callback(err);
if (!result.body) {
return callback(new Error('The response from long running operation does not contain a body.'));
}

if (result.body.properties && result.body.properties.provisioningState) {
pollingState.status = result.body.properties.provisioningState;
} else {
pollingState.status = LroStates.Succeeded;
}

//we might not throw an error, but initialize here just in case.
pollingState.error = {
code: pollingState.status,
message: util.format('Long running operation failed with status \'%s\'.', pollingState.status)
};

pollingState.updateResponse(result.response);
pollingState.request = result.request;
pollingState.resource = result.body;

//nothing to return, the 'pollingState' has all the info we care.
callback(null);
});
Expand All @@ -335,35 +318,35 @@ AzureServiceClient.prototype._updateStateFromGetResourceOperation = function (re
* Retrieve operation status by querying the operation URL.
* @param {string} [operationUrl] - URL used to poll operation result.
*/
AzureServiceClient.prototype._getStatus = function (operationUrl, callback) {
AzureServiceClient.prototype._getStatus = function(operationUrl, callback) {
var self = this;
if (!operationUrl) {
return callback(new Error('operationUrl cannot be null.'));
}

// Construct URL
var requestUrl = operationUrl.replace(' ', '%20');

// Create HTTP transport objects
var httpRequest = new WebResource();
httpRequest.method = 'GET';
httpRequest.headers = {};
httpRequest.url = requestUrl;
if(this._options) {
if (this._options) {
for (var headerName in this._options['customHeaders']) {
if (this._options['customHeaders'].hasOwnProperty(headerName)) {
httpRequest.headers[headerName] = this._options['customHeaders'][headerName];
}
}
}
// Send Request
return self.pipeline(httpRequest, function (err, response, responseBody) {
return self.pipeline(httpRequest, function(err, response, responseBody) {
if (err) {
return callback(err);
}
var statusCode = response.statusCode;
if (statusCode !== 200 && statusCode !== 201 && statusCode !== 202 && statusCode !== 204) {
var error = new Error(util.format('Invalid status code with response body "%s" occurred ' +
var error = new Error(util.format('Invalid status code with response body "%s" occurred ' +
'when polling for operation status.', responseBody));
error.statusCode = response.statusCode;
error.request = msRest.stripRequest(httpRequest);
Expand All @@ -388,8 +371,8 @@ AzureServiceClient.prototype._getStatus = function (operationUrl, callback) {
try {
result.body = JSON.parse(responseBody);
} catch (deserializationError) {
var parseError = new Error(util.format('Error "%s" occurred in deserializing the response body - "%s" -' +
' when polling for operation status.', deserializationError, responseBody));
var parseError = new Error(util.format('Error "%s" occurred in deserializing the response body - "%s" -' +
' when polling for operation status.', deserializationError, responseBody));
parseError.request = msRest.stripRequest(httpRequest);
parseError.response = msRest.stripResponse(response);
parseError.body = responseBody;
Expand Down
Loading

0 comments on commit f058543

Please sign in to comment.