【问题标题】:Awaiting http request in AWS Lambda / Pulumi在 AWS Lambda / Pulumi 中等待 http 请求
【发布时间】:2019-06-14 16:21:11
【问题描述】:

我有一个 AWS Lambda 函数可以触发对 Google API 的 https 请求。我希望该函数是可等待的,以便它不会立即结束,而只是在从 Google API 获得响应之后。 是的,我知道我为执行付费,但不会经常调用,所以没关系。

问题是 http 请求似乎没有正确触发。回调永远不会被执行。

我已通过在 Promise 中使用 setTimeout 确保 async/await 按预期工作。所以问题出在 https.request 中。

另外请注意,我正在使用 Pulumi 部署到 AWS,因此其中可能存在一些隐藏的问题。我就是不知道在哪里。


相关代码:

调用 Google API 的 AWS Lambda

import config from '../../config';
import { IUserInfo } from '../../interfaces';
const https = require('https');

function sendHttpsRequest(options: any): Promise<any> {
    console.log(`sending request to ${options.host}`);
    console.log(`Options are ${JSON.stringify(options)}`);

    return new Promise(function (resolve, reject) {
        console.log(` request to ${options.host} has been sent A`);

        let body = new Array<Buffer>();
        const request = https.request(options, function (res: any) {
            console.log('statusCode:', res.statusCode);
            console.log('headers:', res.headers);

            if (res.statusCode != 200) {
                reject(res.statusCode);
            }

            res.on('data', (data: any) => {
              console.log(`body length is ${body.length}`);
              console.log('data arrived', data);
              body.push(data);
              console.log('pushed to array');
              console.log(data.toString());
            });
        });

        request.on('end', () => {
            console.error('Request ended');
            // at this point, `body` has the entire request body stored in it as a string
            let result = Buffer.concat(body).toString();
            resolve(result);
        });

        request.on('error', async (err: Error) => {
          console.error('Errooooorrrr', err.stack);
          console.error('Errooooorrrr request failed');
          reject(err);
        });

        request.end();

      console.log(` request to ${options.host} has been sent B`);
    });
}

/**
 * AWS Lambda to create new Google account in TopMonks domain
 */
export default async function googleLambdaImplementation(userInfo: IUserInfo) {

    const payload = JSON.stringify({
        "primaryEmail": userInfo.topmonksEmail,
        "name": {
            "givenName": userInfo.firstName,
            "familyName": userInfo.lastName
        },
        "password": config.defaultPassword,
        "changePasswordAtNextLogin": true
    });

    const resultResponse: Response = {
        statusCode: 200,
        body: 'Default response. This should not come back to users'
    }     

    console.log('Calling google api via post request');

    try {
        const options = {
            host: 'www.googleapis.com',
            path: '/admin/directory/v1/users',
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': payload.length.toString()
            },
            form: payload
        }

        const responseFromGoogle = await sendHttpsRequest(options);
        console.log('responseFromGoogle', JSON.stringify(responseFromGoogle));
    }
    catch (err) {
        console.log('Calling google api failed with error', err);
        resultResponse.statusCode = 503;
        resultResponse.body = `Error creating new Google Account for ${userInfo.topmonksEmail}.`;
        return resultResponse;
    }

    console.log('request to google sent');
    return resultResponse;
 }

【问题讨论】:

  • 使用 node-fetch 包
  • @AlešRoubíček 我已经尝试过了。但这是不可能的。 Pulumi 抱怨说,它类似于“无法序列化本机函数”或类似的东西。有问题的部分是 node-fetch 依赖于Symbol.iterator
  • 这里描述了捕获本机函数的问题pulumi.io/reference/serializing-functions.html

标签: node.js amazon-web-services aws-lambda pulumi


【解决方案1】:

问题是 http 请求似乎没有正确触发。回调永远不会执行。

我认为这部分问题与 (a) 可能未实际发送 https 请求和 (b) 未使用 https.request 的正确回调签名的某种组合有关。有关这两个方面的详细信息,请参阅https://nodejs.org/api/https.html#https_https_request_options_callback 的文档。

使用 node-fetch 包

以下示例适用于我使用node-fetch

import * as aws from "@pulumi/aws";
import fetch from "node-fetch";

const api = new aws.apigateway.x.API("api", {
    routes: [{
        method: "GET", path: "/", eventHandler: async (ev) => {
            const resp = await fetch("https://www.google.com");
            const body = await resp.text();
            return {
                statusCode: resp.status,
                body: body,
            }
        },
    }],
})

export const url = api.url;

Pulumi 抱怨说,它类似于“无法序列化本机函数”或类似的东西。有问题的部分是 node-fetch 依赖于 Symbol.iterator

如 cmets 中所述,可能导致此问题的一些条件记录在 https://pulumi.io/reference/serializing-functions.html。但是,我看不出有什么明确的理由说明这段代码会遇到这些限制。可能有关于如何在上面共享的 sn-p 上下文之外使用它的详细信息,从而导致了这种情况。

【讨论】:

  • 感谢您的回答。我试图重写我的脚本,但是当我使用 node-fetch 时,它仍然会导致“可以捕获本机函数 ... bleble ... 在 node-fetch 的某处使用 Symbol.iterator”。您对错误的回调签名是正确的。我会更新我的问题。
  • 好的,解决了。 if (res.statusCode != 200) { reject(res.statusCode); } 行丢失的问题
猜你喜欢
  • 1970-01-01
  • 2015-10-27
  • 2018-11-13
  • 1970-01-01
  • 2017-07-30
  • 2018-05-04
  • 1970-01-01
  • 1970-01-01
  • 2018-11-13
相关资源
最近更新 更多