The Set budgets and budget alerts documentation. You have 2 strategies to deal with this.
The first one is to set an API spending limit either wuota based or limiting the calls per user, so if one fo your services is making an excesive amount of calls to an specific API you just block this API so your entire service/project can keep serving.
The other approach is to automate the disabling of billing for the entire project. This is more risky because it will block the entire project and can cause lost of data.
For this you will deploy a Cloud Function like the one in the documentation triggered by the Pub/Sub topic that your budget is set to use:
const {google} = require('googleapis');
const {GoogleAuth} = require('google-auth-library');
const PROJECT_ID = process.env.GOOGLE_CLOUD_PROJECT;
const PROJECT_NAME = `projects/${PROJECT_ID}`;
const billing = google.cloudbilling('v1').projects;
exports.stopBilling = async pubsubEvent => {
const pubsubData = JSON.parse(
Buffer.from(pubsubEvent.data, 'base64').toString()
);
if (pubsubData.costAmount <= pubsubData.budgetAmount) {
return `No action necessary. (Current cost: ${pubsubData.costAmount})`;
}
if (!PROJECT_ID) {
return 'No project specified';
}
_setAuthCredential();
const billingEnabled = await _isBillingEnabled(PROJECT_NAME);
if (billingEnabled) {
return _disableBillingForProject(PROJECT_NAME);
} else {
return 'Billing already disabled';
}
};
/**
* @return {Promise} Credentials set globally
*/
const _setAuthCredential = () => {
const client = new GoogleAuth({
scopes: [
'https://www.googleapis.com/auth/cloud-billing',
'https://www.googleapis.com/auth/cloud-platform',
],
});
// Set credential globally for all requests
google.options({
auth: client,
});
};
/**
* Determine whether billing is enabled for a project
* @param {string} projectName Name of project to check if billing is enabled
* @return {bool} Whether project has billing enabled or not
*/
const _isBillingEnabled = async projectName => {
try {
const res = await billing.getBillingInfo({name: projectName});
return res.data.billingEnabled;
} catch (e) {
console.log(
'Unable to determine if billing is enabled on specified project, assuming billing is enabled'
);
return true;
}
};
/**
* Disable billing for a project by removing its billing account
* @param {string} projectName Name of project disable billing on
* @return {string} Text containing response from disabling billing
*/
const _disableBillingForProject = async projectName => {
const res = await billing.updateBillingInfo({
name: projectName,
resource: {billingAccountName: ''}, // Disable billing
});
return `Billing disabled: ${JSON.stringify(res.data)}`;
};
Dependencies:
{
"name": "cloud-functions-billing",
"version": "0.0.1",
"dependencies": {
"google-auth-library": "^2.0.0",
"googleapis": "^52.0.0"
}
}
Then you grant the Billing Admin permission to the service account of this Cloud Function
If you want to use this approach I would suggest you in either case to have different projects per service if possible so you can turn off just parts of your service.