【问题标题】:Trying to run a Cloud Function with LRO尝试使用 LRO 运行云函数
【发布时间】:2020-11-10 04:48:00
【问题描述】:

背景 我正在创建一个自主的 Google AutoML 端端系统。我创建了一个云函数,它在训练开始时接收云发布/订阅消息。云函数使用操作ID获取训练的操作状态。如果模型的训练完成(操作元数据 = true),该函数会将模型 ID 发送到部署函数,并发送带有模型 ID 的 pub/sub 消息,以便在预测时调用模型。我从这篇帖子How to programmatically get model id from google-cloud-automl with node.js client library

中找到了一个解决方案

问题 我遇到的问题是云功能超时 10 分钟。我在reddit上写了这个关于潜在解决方案的问题。 https://www.reddit.com/r/googlecloud/comments/jqr213/cloud_function_to_compute_engine/ Compute Engine 解决方案对于主要在云功能环境中编写的系统似乎并不实用。在尝试实现 cron 作业解决方案时,我想到了云功能的重试功能。它保留相同的事件,并将重试该功能长达一周。重试的文档是https://cloud.google.com/functions/docs/bestpractices/retries 我如何包含取消该功能以使其重试直到它变为真并完成部署和发布/订阅消息?我的想法是在 if else 语句中包含系统的结尾,我只是在努力寻找这个/如果它真的有效的文档。

代码

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]

【问题讨论】:

标签: node.js google-cloud-platform google-cloud-functions google-cloud-pubsub automl


【解决方案1】:

您可以考虑对您的代码进行几项改进。首先,重要的是要了解云功能是短暂的。 9 minutes is the maximum,您的功能将处于活动状态。 Cloud Functions 不适用于后台操作,如果您正在寻找可以在后台执行并且需要最少基础架构的解决方案,我建议您查看Cloud Run

现在让我们看一下代码的某些部分,以及如何使用以 Cloud Functions 和 PubSub 作为主干的不同架构进行改进。

等待模型部署

你使用的代码是:

  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);
}

首先,我强烈建议不要在这里使用递归,因为a)这可以通过一个简单的循环来处理,b)您正在轰炸服务而没有任何超时或回退策略。后者可能会导致您的服务崩溃或端点开始拒绝您的请求。

为了改进您的代码,您可以设置至少timeout 函数,如下所示:

setTimeout(getOperationStatus(opped, data), 1000)

为了可读性,我还建议您以后只使用循环,因为无论如何您都在使用async 模式:

status = getOperationStatus(opped, data);
while(!status){
 await new Promise(t => setTimeout(t, 1000));
 status = getOperationStatus(opped, data);
} 

在这种情况下,您需要将其分成两个函数 - 1) getOperationStatus,实际上只是返回状态,以及 2) waitForDeployment,它轮询状态,将其与预期结果进行比较,然后决定a) 等待并重试或 b) 放弃并返回

这可能会使您的代码更好,但不能解决系统设计的根本问题。为了理解这一点,让我们看一下拆分职责和以不同方式构建系统。附带说明一下,here 指南不适用于 Cloud Function 应用程序。

几个解释:

  • Activation Function初始化整个过程,调用Vision Auto ML开始部署。它只获取操作的 ID 并将其推送到队列中
  • Cloud Scheduler 每 X 分钟/秒向 PubSub 推送一个触发器(或者它也可以将函数作为端点调用),表示是时候检查进度了
  • 轮询功能一旦触发要求检查下一个 ID,查询 Cloud AutoML,如果完成,确认消息并写入结果,否则退出。您需要注意此处的确认配置。有用的信息是here

状态轮询 我注意到的一件小事是您如何轮询状态。为什么不直接查询这个 URL GET https://automl.googleapis.com/v1/projects/project-id/locations/us-central1/operations/operation-id 并获得完成状态(查看here 了解详情)

结论:云函数是短暂的,一次只能处理一个操作,无需等待。如果您想要一个简单的循环来等待结果,请使用 Cloud Run

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2020-11-13
    • 2014-11-07
    • 2021-05-06
    • 1970-01-01
    • 2021-09-25
    • 2020-08-15
    相关资源
    最近更新 更多