在GCP
上,我创建了一个CloudFunction
,它由Pub/Sub
的计费事件触发,并在Slack上发布一些消息。我正在使用node.js 10
。我有以下依赖项:
{
"name": "google-container-slack",
"version": "0.0.1",
"description": "Slack integration for Google Cloud Build, using Google Cloud Functions",
"main": "index.js",
"dependencies": {
"@slack/webhook": "5.0.3",
"@google-cloud/bigquery": "4.7.0",
"@google-cloud/pubsub": "1.6.0"
}
}
当我在BigQuery
中添加一个函数来编写新的预算信息时,我遇到了一些问题,该函数基于一些官方示例:https://github.com/googleapis/nodejs-bigquery/blob/master/samples/insertRowsAsStream.js
// writeInBigQuery update BigQuery table
async function writeInBigQuery(pubsubdata, createdAt, project, threshold) {
const bigquery = new BigQuery({projectId: billing_project});
const rows = [{createdAt: createdAt},
{budgetAmount:pubsubdata.budgetAmount},
{projectName: project},
{thresholdValue: threshold}];
console.log(rows);
console.log('start insert row in bigquery');
await bigquery
.dataset(dataset)
.table(table)
.insert(rows);
console.log('end insert row in bigquery');
console.log(`Inserted ${rows.length} rows`);
}
我的猜测是,这个问题与异步和等待有关。这是我使用node.js的第一个代码,错误消息对我来说很神秘:
Function execution took 266 ms, finished with status: 'ok'
Unhandled rejection
PartialFailureError
at request (/layers/google.nodejs.npm/npm/node_modules/@google-cloud/bigquery/build/src/table.js:1550:23)
at util.makeRequest.params (/layers/google.nodejs.npm/npm/node_modules/@google-cloud/common/build/src/util.js:367:25)
8 at Util.handleResp (/layers/google.nodejs.npm/npm/node_modules/@google-cloud/common/build/src/util.js:144:9)
8 at retryRequest (/layers/google.nodejs.npm/npm/node_modules/@google-cloud/common/build/src/util.js:432:22)
at onResponse (/layers/google.nodejs.npm/npm/node_modules/retry-request/index.js:206:7)
8 at /layers/google.nodejs.npm/npm/node_modules/teeny-request/build/src/index.js:233:13
at process._tickCallback (internal/process/next_tick.js:68:7)
8 Error: Process exited with code 16
at process.on.code (/layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/invoker.js:393:29)
at process.emit (events.js:198:13)
at process.EventEmitter.emit (domain.js:448:20)
at process.exit (internal/process/per_thread.js:168:15)
at logAndSendError (/layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/invoker.js:184:9)
at process.on.err (/layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/invoker.js:390:13)
at process.emit (events.js:198:13)
at process.EventEmitter.emit (domain.js:448:20)
at emitPromiseRejectionWarnings (internal/process/promises.js:140:18)
at process._tickCallback (internal/process/next_tick.js:69:34)
也许这个问题与代码的整体结构有关:
const { IncomingWebhook } = require('@slack/webhook');
const {BigQuery} = require('@google-cloud/bigquery');
const url = process.env.SLACK_WEBHOOK_URL;
const project =process.env.PROJECT_LIST.split(',');
const dataset = process.env.DATASET;
const table = process.env.TABLE;
const billing_project = process.env.PROJECT;
const webhook = new IncomingWebhook(url);
// subscribeSlack is the main function called by Cloud Functions.
module.exports.subscribeSlack= (pubSubEvent, context) => {
const pubsubdata = eventToBuild(pubSubEvent.data);
//select for which project to send budget alert
if (project.indexOf(pubsubdata.budgetDisplayName) === -1) {
console.log(`skip project: ${pubsubdata.budgetDisplayName.substr(0,pubsubdata.budgetDisplayName.indexOf(' '))}`);
return;
}
console.log(`project: ${pubsubdata.budgetDisplayName.substr(0,pubsubdata.budgetDisplayName.indexOf(' '))}`);
// Send message to Slack.
const message = createSlackMessage(pubsubdata);
webhook.send(message);
};
// eventToBuild transforms pubsub event message to a build object.
const eventToBuild = (data) => {
return JSON.parse(Buffer.from(data, 'base64').toString());
}
// writeInBigQuery update BigQuery table
async function writeInBigQuery(pubsubdata, createdAt, project, threshold) {
const bigquery = new BigQuery({projectId: billing_project});
const rows = [{createdAt: createdAt},
{budgetAmount:pubsubdata.budgetAmount},
{projectName: project},
{thresholdValue: threshold}];
console.log(rows);
console.log('start insert row in bigquery');
await bigquery
.dataset(dataset)
.table(table)
.insert(rows);
console.log('end insert row in bigquery');
console.log(`Inserted ${rows.length} rows`);
}
// createSlackMessage creates a message from a build object.
const createSlackMessage = (pubsubdata) => {
const formatter = new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR', minimumFractionDigits: 2})
const costAmount = formatter.format(pubsubdata.costAmount);
const budgetAmount = formatter.format(pubsubdata.budgetAmount);
const budgetName = pubsubdata.budgetDisplayName;
const createdAt = new Date().toISOString();
const project = budgetName.substr(0,budgetName.indexOf(' '))
let threshold = (pubsubdata.alertThresholdExceeded*100).toFixed(0);
if (!isFinite(threshold)){
threshold = 0;
}
// write current budget info in BigQuery
console.log('big query call start');
writeInBigQuery(pubsubdata, createdAt, project, threshold);
console.log('big query call end');
// create Slack message
const emoticon = threshold >= 90 ? ':fire:' : ':white_check_mark:';
notification = `${emoticon} Project: ${project}nOverall cost: ${costAmount} nTotal Budget: ${budgetAmount}nThresold: ${threshold}%`
const message = {
text: notification
};
return message;
}
这个问题与asyn ... wait
无关,而是我准备在BigQuery:中写入数据时的一个错误
const rows = [{createdAt: createdAt},
{budgetAmount:pubsubdata.budgetAmount},
{projectName: project},
{thresholdValue: threshold}];
应该是:
const rows = [{createdAt: createdAt,
budgetAmount:pubsubdata.budgetAmount,
projectName: project,
thresholdValue: threshold}];
有了这个修复程序,一切正常。
最终和正在工作的发现可以在这里找到:index.js