diff --git a/lib/api.js b/lib/api.js index 94cfd64a..bb911de4 100644 --- a/lib/api.js +++ b/lib/api.js @@ -194,13 +194,28 @@ var api = { reqOptions.qs = options.qs; reqOptions.headers = options.headers; + var requestFunction = function() { + return _request(reqOptions); + }; if (options.auth === true) { - return api.addRequestHeaders(reqOptions).then(function(reqOptionsWithToken) { - return _request(reqOptionsWithToken); - }); + requestFunction = function() { + return api.addRequestHeaders(reqOptions).then(function(reqOptionsWithToken) { + return _request(reqOptionsWithToken); + }); + }; } - return _request(reqOptions); + return requestFunction().catch(function(err) { + if ( + options.retryCodes && + _.includes(options.retryCodes, _.get(err, "context.response.statusCode")) + ) { + return new Promise(function(resolve) { + setTimeout(resolve, 1000); + }).then(requestFunction); + } + return Promise.reject(err); + }); }, getProject: function(projectId) { return api diff --git a/lib/gcp/cloudfunctions.js b/lib/gcp/cloudfunctions.js index 6df1a877..82f766c6 100644 --- a/lib/gcp/cloudfunctions.js +++ b/lib/gcp/cloudfunctions.js @@ -26,11 +26,13 @@ function _functionsOpLogReject(func, type, err) { function _generateUploadUrl(projectId, location) { var parent = "projects/" + projectId + "/locations/" + location; var endpoint = "/" + API_VERSION + "/" + parent + "/functions:generateUploadUrl"; + return api .request("POST", endpoint, { auth: true, json: false, origin: api.functionsOrigin, + retryCodes: [503], }) .then( function(result) { diff --git a/lib/gcp/runtimeconfig.js b/lib/gcp/runtimeconfig.js index d2ec871d..87587046 100644 --- a/lib/gcp/runtimeconfig.js +++ b/lib/gcp/runtimeconfig.js @@ -8,127 +8,116 @@ var _ = require("lodash"); var API_VERSION = "v1beta1"; -function _retryOnServerError(requestFunction) { - return requestFunction().catch(function(err) { - if (_.includes([500, 503], _.get(err, "context.response.statusCode"))) { - return new Promise(function(resolve) { - setTimeout(resolve, 1000); - }).then(requestFunction); - } - return Promise.reject(err); - }); -} - function _listConfigs(projectId) { - return _retryOnServerError(function() { - return api.request("GET", utils.endpoint([API_VERSION, "projects", projectId, "configs"]), { + return api + .request("GET", utils.endpoint([API_VERSION, "projects", projectId, "configs"]), { auth: true, origin: api.runtimeconfigOrigin, + retryCodes: [500, 503], + }) + .then(function(resp) { + return Promise.resolve(resp.body.configs); }); - }).then(function(resp) { - return Promise.resolve(resp.body.configs); - }); } function _createConfig(projectId, configId) { var path = _.join(["projects", projectId, "configs"], "/"); var endpoint = utils.endpoint([API_VERSION, path]); - return _retryOnServerError(function() { - return api.request("POST", endpoint, { + return api + .request("POST", endpoint, { auth: true, origin: api.runtimeconfigOrigin, data: { name: path + "/" + configId, }, + retryCodes: [500, 503], + }) + .catch(function(err) { + if (_.get(err, "context.response.statusCode") === 409) { + // Config has already been created as part of a parallel operation during firebase functions:config:set + return Promise.resolve(); + } + return Promise.reject(err); }); - }).catch(function(err) { - if (_.get(err, "context.response.statusCode") === 409) { - // Config has already been created as part of a parallel operation during firebase functions:config:set - return Promise.resolve(); - } - return Promise.reject(err); - }); } function _deleteConfig(projectId, configId) { - return _retryOnServerError(function() { - return api.request( - "DELETE", - utils.endpoint([API_VERSION, "projects", projectId, "configs", configId]), - { - auth: true, - origin: api.runtimeconfigOrigin, + return api + .request("DELETE", utils.endpoint([API_VERSION, "projects", projectId, "configs", configId]), { + auth: true, + origin: api.runtimeconfigOrigin, + retryCodes: [500, 503], + }) + .catch(function(err) { + if (_.get(err, "context.response.statusCode") === 404) { + logger.debug("Config already deleted."); + return Promise.resolve(); } - ); - }).catch(function(err) { - if (_.get(err, "context.response.statusCode") === 404) { - logger.debug("Config already deleted."); - return Promise.resolve(); - } - return Promise.reject(err); - }); + return Promise.reject(err); + }); } function _listVariables(configPath) { - return _retryOnServerError(function() { - return api.request("GET", utils.endpoint([API_VERSION, configPath, "variables"]), { + return api + .request("GET", utils.endpoint([API_VERSION, configPath, "variables"]), { auth: true, origin: api.runtimeconfigOrigin, + retryCodes: [500, 503], + }) + .then(function(resp) { + return Promise.resolve(resp.body.variables); }); - }).then(function(resp) { - return Promise.resolve(resp.body.variables); - }); } function _getVariable(varPath) { - return _retryOnServerError(function() { - return api.request("GET", utils.endpoint([API_VERSION, varPath]), { + return api + .request("GET", utils.endpoint([API_VERSION, varPath]), { auth: true, origin: api.runtimeconfigOrigin, + retryCodes: [500, 503], + }) + .then(function(resp) { + return Promise.resolve(resp.body); }); - }).then(function(resp) { - return Promise.resolve(resp.body); - }); } function _createVariable(projectId, configId, varId, value) { var path = _.join(["projects", projectId, "configs", configId, "variables"], "/"); var endpoint = utils.endpoint([API_VERSION, path]); - return _retryOnServerError(function() { - return api.request("POST", endpoint, { + return api + .request("POST", endpoint, { auth: true, origin: api.runtimeconfigOrigin, data: { name: path + "/" + varId, text: value, }, + retryCodes: [500, 503], + }) + .catch(function(err) { + if (_.get(err, "context.response.statusCode") === 404) { + // parent config doesn't exist yet + return _createConfig(projectId, configId).then(function() { + return _createVariable(projectId, configId, varId, value); + }); + } + return Promise.reject(err); }); - }).catch(function(err) { - if (_.get(err, "context.response.statusCode") === 404) { - // parent config doesn't exist yet - return _createConfig(projectId, configId).then(function() { - return _createVariable(projectId, configId, varId, value); - }); - } - return Promise.reject(err); - }); } function _updateVariable(projectId, configId, varId, value) { var path = _.join(["projects", projectId, "configs", configId, "variables", varId], "/"); var endpoint = utils.endpoint([API_VERSION, path]); - return _retryOnServerError(function() { - return api.request("PUT", endpoint, { - auth: true, - origin: api.runtimeconfigOrigin, - data: { - name: path, - text: value, - }, - }); + return api.request("PUT", endpoint, { + auth: true, + origin: api.runtimeconfigOrigin, + data: { + name: path, + text: value, + }, + retryCodes: [500, 503], }); } - function _setVariable(projectId, configId, varId, value) { var path = _.join(["projects", projectId, "configs", configId, "variables", varId], "/"); return _getVariable(path) @@ -147,18 +136,19 @@ function _deleteVariable(projectId, configId, varId) { var endpoint = utils.endpoint([API_VERSION, "projects", projectId, "configs", configId, "variables", varId]) + "?recursive=true"; - return _retryOnServerError(function() { - return api.request("DELETE", endpoint, { + return api + .request("DELETE", endpoint, { auth: true, origin: api.runtimeconfigOrigin, + retryCodes: [500, 503], + }) + .catch(function(err) { + if (_.get(err, "context.response.statusCode") === 404) { + logger.debug("Variable already deleted."); + return Promise.resolve(); + } + return Promise.reject(err); }); - }).catch(function(err) { - if (_.get(err, "context.response.statusCode") === 404) { - logger.debug("Variable already deleted."); - return Promise.resolve(); - } - return Promise.reject(err); - }); } module.exports = { diff --git a/scripts/test-functions-config.js b/scripts/test-functions-config.js index 232ad5c1..dec198c4 100644 --- a/scripts/test-functions-config.js +++ b/scripts/test-functions-config.js @@ -3,6 +3,7 @@ var chalk = require("chalk"); var exec = require("child_process").exec; +var execSync = require("child_process").execSync; var expect = require("chai").expect; var fs = require("fs-extra"); var tmp = require("tmp"); @@ -21,6 +22,7 @@ var preTest = function() { fs.copySync(projectDir, tmpDir); api.setRefreshToken(configstore.get("tokens").refresh_token); api.setScopes(scopes.CLOUD_PLATFORM); + execSync(localFirebase + " functions:config:unset foo", { cwd: tmpDir }); console.log("Done pretest prep."); };