【问题标题】:Google Cloud Function in Javascript completes before the function is completedJavascript 中的 Google Cloud 函数在函数完成之前完成
【发布时间】:2020-03-02 05:46:43
【问题描述】:

为了解释我的用例,我有一个 GCP 计算引擎,它运行一个支持 RESTful API 的内部构建的应用程序。我要做的是阅读 RESTful API 以检查应用程序中的记录是否有任何更新。

如果有新记录,我想将其添加到用于在 Data Studio 中构建报告的 BigQUery 表中。

我有一个问题,即函数在 BigQuery 中的插入完成之前完成。我添加了异步,等待我似乎没有为我的这项工作找到正确的公式,所以我转向社区寻求输入。我很感激我能得到的任何建议。这是我的代码 ` '使用严格';

 // Request Data From A URL
 var axios = require('axios');
 var https = require('https');

  // Var Firebase Functions
 var functions = require('firebase-functions');
 const admin = require('firebase-admin');

 // Initalise App
 admin.initializeApp;

// Setting Timeout in Seconds - default is 1 second
// The maximum value for timeoutSeconds is 540, or 9 minutes. Valid values for memory are:
// 128MB, 256MB, 512MB, 1GB, 2GB

const runtimeOpts = {
  timeoutSeconds: 300,
  memory: '512MB'
}

exports.getEmilyNoonreporttoBigQuery = functions
  .runWith(runtimeOpts)
  .region('europe-west1')
  .https.onRequest(async(req, res) => {
   try {
   // Imports the Google Cloud client library
   const {BigQuery} = require('@google-cloud/bigquery');

  // Create a client
  const bigquery = new BigQuery();

  //Make use of a dataset
  const dataset = bigquery.dataset('noonreport');

//Make use of a table
const table = dataset.table('noonreport');

// The API Key
  let apikey = 'API-KEY';

  // Table to get data from
  var apitable = 'noon_report';

  // From were the data comes
  var shipid = '1';

  // Get the current date 
  var today = new Date();
  var dd = String(today.getDate()).padStart(2, '0');
  var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
  var yyyy = today.getFullYear();

  today = yyyy + '-' + mm + '-' + dd;

  var url = 'https://emily.apps.gl3/api/' + shipid + '/' + apitable + '?apikey=' + apikey + '&syncdate=' + today;
  console.log('today', today);
  console.log('url', url);

  // At request level
  const agent = new https.Agent({  
    rejectUnauthorized: false
  });

//  axios.get(url)
axios.get(url, { httpsAgent: agent })
    .then(resp => {
      try {
      console.log("Response " + resp);
      for(let artno in resp.data.noon_report) {
        // Create the BigQuery Row
          var row = {
            ship: resp.data.noon_report[artno].noon_report.ship,
            local_time: resp.data.noon_report[artno].noon_report.local_time || resp.data.noon_report[artno].noon_report.report_date,
            status: resp.data.noon_report[artno].noon_report.status,
            location: resp.data.noon_report[artno].noon_report.location,
            course: resp.data.noon_report[artno].noon_report.course,
            next_port: resp.data.noon_report[artno].noon_report.next_port,
            ETD: resp.data.noon_report[artno].noon_report.ETD,
            ETA: resp.data.noon_report[artno].noon_report.ETA,
            distance_made: resp.data.noon_report[artno].noon_report.distance_made,
            stoppage: resp.data.noon_report[artno].noon_report.stoppage,
            avg_speed: resp.data.noon_report[artno].noon_report.avg_speed,  
            mgo_rob: resp.data.noon_report[artno].noon_report.mgo_rob,
            mgo_consumed: resp.data.noon_report[artno].noon_report.mgo_consumed,
            mgo_received: resp.data.noon_report[artno].noon_report.mgo_received,
            fw_rob: resp.data.noon_report[artno].noon_report.fw_rob,
            fw_consumed: resp.data.noon_report[artno].noon_report.fw_consumed,
            fw_produced: resp.data.noon_report[artno].noon_report.fw_produced,
            fw_received: resp.data.noon_report[artno].noon_report.fw_received,
            underway_hours: resp.data.noon_report[artno].noon_report.underway_hours,
            me_rh: resp.data.noon_report[artno].noon_report.me_rh,
            heli_flight_hours: resp.data.noon_report[artno].noon_report.heli_flight_hours,
            heli_fuel_consumed: resp.data.noon_report[artno].noon_report.heli_fuel_consumed,
            heli_fuel_rob: resp.data.noon_report[artno].noon_report.heli_fuel_rob,
            name_of_pilot: resp.data.noon_report[artno].noon_report.name_of_pilot,
            nature_of_flight: resp.data.noon_report[artno].noon_report.nature_of_flight,
            wind_direction: resp.data.noon_report[artno].noon_report.wind_direction,
            wind_force: resp.data.noon_report[artno].noon_report.wind_force,
            sea_state: resp.data.noon_report[artno].noon_report.sea_state,
            weather: resp.data.noon_report[artno].noon_report.weather,
            visibility: resp.data.noon_report[artno].noon_report.visibility,
            barometer: resp.data.noon_report[artno].noon_report.barometer,
            air_temp: resp.data.noon_report[artno].noon_report.air_temp,
            remarks: resp.data.noon_report[artno].noon_report.remarks,
            cur_timestamp: resp.data.noon_report[artno].noon_report.cur_timestamp,
            cancelled: resp.data.noon_report[artno].noon_report.cancelled,
            arrivaldep: resp.data.noon_report[artno].noon_report.arrivaldep,
            shorepw: resp.data.noon_report[artno].noon_report.shorepw,  
            lo_rob: resp.data.noon_report[artno].noon_report.lo_rob,
            lo_consumed: resp.data.noon_report[artno].noon_report.lo_consumed,
            petrol_rob: resp.data.noon_report[artno].noon_report.petrol_rob,
            petrol_consumed: resp.data.noon_report[artno].noon_report.petrol_consumed,
            heli_fuel_received: resp.data.noon_report[artno].noon_report.heli_fuel_received,
            petrol_received: resp.data.noon_report[artno].noon_report.petrol_received,
            lo_received: resp.data.noon_report[artno].noon_report.lo_received,
            campaign: resp.data.noon_report[artno].noon_report.campaign,
            projectLeader: resp.data.noon_report[artno].noon_report.projectLeader,
            visitorsOpen: resp.data.noon_report[artno].noon_report.visitorsOpen,
            fundsOpen: resp.data.noon_report[artno].noon_report.fundsOpen,
            vipsOpen: resp.data.noon_report[artno].noon_report.vipsOpen,
            pressOpen: resp.data.noon_report[artno].noon_report.pressOpen,
            volsOpen: resp.data.noon_report[artno].noon_report.volsOpen,
            officeOpen: resp.data.noon_report[artno].noon_report.officeOpen,
            clockChange: resp.data.noon_report[artno].noon_report.clockChange,
            operPrepared: resp.data.noon_report[artno].noon_report.operPrepared,
            techPrepared: resp.data.noon_report[artno].noon_report.techPrepared,
            port_of_call: resp.data.noon_report[artno].noon_report.port_of_call|| "No Author Defined",
            time_zone: resp.data.noon_report[artno].noon_report.time_zone,
            report_date: resp.data.noon_report[artno].noon_report.report_date,
            report_by: resp.data.noon_report[artno].noon_report.report_by,
            berth_anchor_hours: resp.data.noon_report[artno].noon_report.berth_anchor_hours,
            ship_activity: resp.data.noon_report[artno].noon_report.ship_activity,
            uuid: resp.data.noon_report[artno].noon_report.uuid,
            is_submit: resp.data.noon_report[artno].noon_report.is_submit,
            helicopter_used: resp.data.noon_report[artno].noon_report.helicopter_used,
            position_lat: resp.data.noon_report[artno].noon_report.position_lat,
            position_lon: resp.data.noon_report[artno].noon_report.position_lon,
            me1_distance: resp.data.noon_report[artno].noon_report.me1_distance,
            me1_uw_hours: resp.data.noon_report[artno].noon_report.me1_uw_hours,
            me2_distance: resp.data.noon_report[artno].noon_report.me2_distance,
            me2_uw_hours: resp.data.noon_report[artno].noon_report.me2_uw_hours,
            me1_2_distance: resp.data.noon_report[artno].noon_report.me1_2_distance,
            me1_2_uw_hours: resp.data.noon_report[artno].noon_report.me1_2_uw_hours,
            edrive_distance: resp.data.noon_report[artno].noon_report.edrive_distance,
            edrive_uw_hours: resp.data.noon_report[artno].noon_report.edrive_uw_hours,
            sail_distance: resp.data.noon_report[artno].noon_report.sail_distance,
            sail_uw_hours: resp.data.noon_report[artno].noon_report.sail_uw_hours,
            e_motorsail_distance: resp.data.noon_report[artno].noon_report.e_motorsail_distance,
            e_motorsail_uw_hours: resp.data.noon_report[artno].noon_report.e_motorsail_uw_hours,
            me_motorsail_distance: resp.data.noon_report[artno].noon_report.me_motorsail_distance,
            me_motorsail_uw_hours: resp.data.noon_report[artno].noon_report.me_motorsail_uw_hours,
            motoring_edrive_distance: resp.data.noon_report[artno].noon_report.motoring_edrive_distance,
            motoring_edrive_uw_hours: resp.data.noon_report[artno].noon_report.motoring_edrive_uw_hours,
            drifting_hours: resp.data.noon_report[artno].noon_report.drifting_hours,
            country: resp.data.noon_report[artno].noon_report.author          
          };
          console.log("ROW TO INSERT " + JSON.stringify(row));
          insertBigQuery(row, table);
        }
        console.log("For Loop end");
        res.status(200).send("OK");
      }
      catch (error) {
        // Handle the error
        console.log(error);
        response.status(500).send(error);
      }
    })
  }
  catch (error) {
      // Handle the error
      console.log(error);
      response.status(500).send(error);
    }

    //This Query inserts data after charges completed
    async function insertBigQuery(row, table){
     return await table.insert(row, function(err, apiResponse) {
        //console.log('Insert', apiResponse);
        if (!err) {
         console.log("[BIGQUERY] - Saved.");
        } else {
        console.error(`error table.insert: ${JSON.stringify(err)}`)
         // To finish http function return value
        }
      });
    }
});

`

我有一个 for 循环来解压缩 RESTFul API 数据并构建一行以插入 BigQuery。我使用 Cloud scheduler 通过 HTTP 触发器来触发此功能。

我使用的 URL 用于内部应用程序,因此在外部不可用。我得到数据并解压数据,函数在数据插入 BigQuery 之前完成。

我尝试在调用 BigQuery 插入函数的行中添加等待,但没有成功。

await insertBigQuery(row, table);

没用,求帮助。

【问题讨论】:

  • await 添加到insertBigQuery 是朝着正确方向迈出的一步,您是否还向箭头函数async resp => 添加了async(第66 行)。如果这没有帮助,我建议在代码的重要位置添加一些日志打印并共享它们,这有助于识别问题。为了获得最佳实践,我建议不要将var 用于行,而是使用let 并在for loop 之外定义let。我通常会避免直接从 insertBigQuery 返回 await ,而是将结果放入 let 中,这样可以更轻松地调试代码

标签: javascript rest api google-bigquery google-cloud-functions


【解决方案1】:

我想我看到了几个问题。如果我们查看名为 insert 的 BigQuery 表对象的 API,我们会看到它返回了一个 Promise。伟大的。我们还看到它有一个可选的回调函数。我不确定您是否应该同时使用两者。你要么说结果将是一个随后将被解决的承诺,要么你说结果将通过回调告诉你。我不确定双方都会满意。我建议只使用 Promises。

但是,我认为更大的问题在于这个逻辑:

async function insertBigQuery(row, table){
  return await table.insert(row, function(err, apiResponse) {
    //console.log('Insert', apiResponse);
    if (!err) {
      console.log("[BIGQUERY] - Saved.");
     } else {
       console.error(`error table.insert: ${JSON.stringify(err)}`)
       // To finish http function return value
     }
  });
}

解决这个问题......你有:

async function funcName() {
   return await asyncFuncCall();
}

我认为这可能是您的问题。通过在您的函数 (funcName) 前加上 async,您声明该函数将返回 Promise,并且调用者不会阻塞等待返回,但调用者本身会收到一个承诺。

我偷偷地怀疑你真正想要的是:

async function funcName() {
   return asyncFuncCall();
}

然后你想要调用 funcName() 的地方:

let finalResult = await funcName();

funcName().then((finalResult) => { ... logic ... });

【讨论】:

  • 谢谢,我会试试你的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
  • 2017-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多