Node.js 尝试使用LRO运行云函数
背景 我正在创建一个自主的Google AutoML End系统。我创建了一个云函数,在培训开始时接收一条云发布/订阅消息。云函数使用操作ID获取培训的操作状态。如果模型的培训完成(operation metadata=true),该函数将向部署函数发送模型ID,并发送带有模型ID的发布/订阅消息,以便在预测时从中调用模型。我从这篇文章中找到了一个解决方案 问题 我遇到的问题是云功能超时10分钟。我在reddit上写了这个关于潜在解决方案的问题。对于主要在云功能环境中编写的系统来说,计算引擎解决方案似乎不实用。在尝试实现cron作业解决方案时,我想到了云函数的重试功能。它将保留相同的事件,并将重试该函数长达一周。关于重试的文档是,我怎样才能包含一个函数的取消,以使它一直重试,直到它变为真并完成部署和发布/订阅消息?我的想法是在if-else语句中包含系统的结尾,我只是在努力寻找这个/如果它真的能工作的文档 代码Node.js 尝试使用LRO运行云函数,node.js,google-cloud-platform,google-cloud-functions,google-cloud-pubsub,automl,Node.js,Google Cloud Platform,Google Cloud Functions,Google Cloud Pubsub,Automl,背景 我正在创建一个自主的Google AutoML End系统。我创建了一个云函数,在培训开始时接收一条云发布/订阅消息。云函数使用操作ID获取培训的操作状态。如果模型的培训完成(operation metadata=true),该函数将向部署函数发送模型ID,并发送带有模型ID的发布/订阅消息,以便在预测时从中调用模型。我从这篇文章中找到了一个解决方案 问题 我遇到的问题是云功能超时10分钟。我在reddit上写了这个关于潜在解决方案的问题。对于主要在云功能环境中编写的系统来说,计算引擎解决
const {AutoMlClient} = require('@google-cloud/automl').v1;
// Instantiates a client
const client = new AutoMlClient();
exports.helloPubSub = (event, context) => {
//Imports the Google Cloud AutoML library
const message = event.data
? Buffer.from(event.data, 'base64').toString()
: 'Hello, World';
const model = message;
console.log(model);
const modelpath = message.replace('"','');
const modelID = modelpath.replace('"','');
const message1 = model.replace('projects/170974376642/locations/us-central1/operations/','');
const message2 = message1.replace('"','');
const message3 = message2.replace('"','');
console.log(`Operation ID is: ${message3}`)
getOperationStatus(message3, modelID);
}
// [START automl_vision_classification_deploy_model_node_count]
async function getOperationStatus(opId, message) {
console.log('Starting operation status');
const opped = opId;
const data = message;
const projectId = '170974376642';
const location = 'us-central1';
const operationId = opId;
// Construct request
const request = {
name: `${message}`,
};
console.log('Made it to the response');
const [response] = await client.operationsClient.getOperation(request);
console.log(`Name: ${response.name}`);
console.log(`Operation details:`);
var apple = JSON.stringify(response);
console.log(apple);
console.log('Loop until the model is ready to deploy');
if (apple.includes('True')) {
const appleF = apple.replace((/projects\/[a-zA-Z0-9-]*\/locations\/[a-zA-Z0-9-]*\/models\//,''));
deployModelWithNodeCount(appleF);
pubSub(appleF);
} else {
getOperationStatus(opped, data);
}
}
async function pubSub(id) {
const topicName = 'modelID';
const data = JSON.stringify({foo: `${id}`});
async function publishMessage() {
// Publishes the message as a string, e.g. "Hello, world!" or JSON.stringify(someObject)
const dataBuffer = Buffer.from(data);
try {
const messageId = await pubSubClient.topic(topicName).publish(dataBuffer);
console.log(`Message ${messageId} published.`);
} catch (error) {
console.error(`Received error while publishing: ${error.message}`);
process.exitCode = 1;
}
}
publishMessage();
// [END pubsub_publish_with_error_handler]
// [END pubsub_quickstart_publisher]
process.on('unhandledRejection', err => {
console.error(err.message);
process.exitCode = 1;
});
}
async function deployModelWithNodeCount(message) {
const projectId = 'ireda1';
const location = 'us-central1';
const modelId = message;
// Construct request
const request = {
name: client.modelPath(projectId, location, modelId),
imageClassificationModelDeploymentMetadata: {
nodeCount: 1,
},
};
const [operation] = await client.deployModel(request);
// Wait for operation to complete.
const [response] = await operation.promise();
console.log(`Model deployment finished. ${response}`);
}
// [END automl_vision_classification_deploy_model_node_count]
<> P>有几个改进,你可以考虑你的代码。首先,重要的是要理解云功能是短暂的,您的功能将被激活。云功能并不适用于后台操作,如果您正在寻找一种解决方案,它可以在后台执行,并且需要最少的基础设施,我建议您看看 现在让我们看一下代码的一些部分,以及如何使用不同的体系结构来维护云功能和PubSub作为主干来改进代码 等待模型部署 您使用的代码是:
if(apple.includes('True'){
const appleF=apple.replace(/projects\/[a-zA-Z0-9-]*\/locations\/[a-zA-Z0-9-]*\/models\/,'');
deployModelWithNodeCount(appleF);
pubSub(appleF);
}否则{
getOperationStatus(opped,数据);
}
首先,我强烈建议不要在这里使用递归,因为a)这可以通过一个简单的循环来处理,b)您在没有任何超时或退避策略的情况下轰炸服务。后者可能导致服务崩溃或端点开始拒绝您的请求
为了改进代码,例如,您可以设置至少一个函数,如下所示:
setTimeout(getOperationStatus(opped,数据),1000)
为了可读性,我还建议以后只使用循环,因为您正在使用async
模式:
status=getOperationStatus(opped,数据);
而(!状态){
等待新的承诺(t=>setTimeout(t,1000));
状态=getOperationStatus(opped,数据);
}
在这种情况下,您需要将其分为两个函数-1)getOperationStatus
,它实际上只返回状态;2)waitForDeployment
,它轮询状态,将其与预期结果进行比较,并决定a)等待并重试,或b)放弃并返回
这可能会使您的代码更好,但不能解决系统设计的根本问题。为了理解这一点,让我们看一看责任划分和以不同的方式构建系统。作为旁注,本指南并不适用于云功能应用程序。
一些解释:
- 激活功能初始化整个过程,它调用Vision Auto ML启动部署。它只获取操作的ID并将其推送到队列
- Cloud Scheduler每隔X分钟/秒向PubSub推送一个触发器(或者它也可以作为端点调用该函数),表示是时候检查进度了
- 轮询功能一旦触发,请求检查下一个ID,查询Cloud AutoML,如果完成,确认消息并写入结果,否则退出。您需要小心此处的确认配置。有用的信息是
GEThttps://automl.googleapis.com/v1/projects/project-id/locations/us-central1/operations/operation-id
并获取完成状态(查看详细信息)
结论:云函数的寿命很短,一次只能处理一个操作,无需等待。如果您想要一个等待结果的简单循环,请使用cloudrun
我已经尝试实现console.log('函数正在停止以重试');返回承诺。拒绝(错误);这将结束函数,并且不会记录任何重试