异步代码独立工作,但不能一起工作。没有任何异常,只是超时

Posted

技术标签:

【中文标题】异步代码独立工作,但不能一起工作。没有任何异常,只是超时【英文标题】:Asynchronous code works independently, but not together. Not getting any exceptions, just timing out 【发布时间】:2022-01-20 15:56:53 【问题描述】:

我正在编写一个 lambda 函数来将主机添加到 SQS 队列以进行滚动重启。我编写的代码单独工作,但不能一起工作。即使我在构造函数中硬编码值。这似乎不是内存/CPU。我尝试使用 1GB 内存运行该函数,尽管它只使用了大约 80MB。单个函数的平均执行时间约为 0.5 秒(总共执行时间不应超过 1.5 秒)。我曾尝试以 30 秒的超时时间运行此函数,但它仍然超时。

我在公司代理后面工作,不得不手动编写代码。我的面向 Internet 的网络上没有 IDE 或智能感知。这里可能有错别字,但实际代码中没有。我省略了模块导入和变量声明以节省时间。它与手头的问题无关。

编辑:我在第一个示例中添加了模块导入和变量声明,希望能减轻一些混乱。

这里只是我尝试过的一些事情。这不起作用(超时):

// Custom lambda layer
const  marklogic, aws  = require('nodejs-layer-lib'); 
const  HOSTS, DOMAIN, PORT, USERNAME, PASSWORD, RESTART_QUEUE_NAME  = process.env;

const params = [
  'format=json'
];

const options = 
  port: PORT,
  params: params,
  httpOptions: 
    headers: 
       'Authorization': `Basic $Buffer.from(`$USERNAME:$PASSWORD`).toString('base64')`
    ,
    method: 'GET'
  
;

const taskServers = (HOSTS.split(',') || []).map(host => 
  const _host = host.split(':');

  return 
    id: _host[0],
    name: `http://$_host[1].toLowerCase().$DOMAIN`
  ;
);

exports.handler = async () => 
  let hosts, queueUrl, addToQueueResults;

  try 
    hosts = (await marklogic.hosts.getHosts(taskServers, options) || []);
   catch (e)  console.error('hosts', e); 

  try 
    queueUrl = await aws.sqs.getQueueUrlByName(RESTART_QUEUE_NAME);
   catch (e)  console.error('queueUrl ', e); 

  try 
    addToQueueResults = await aws.sqs.addMessages(queueURL, hosts);
   catch (e)  console.error('addToQueueResults ', e); 

  return 
    status: 200,
    body: addToQueueResults
  ;

这不起作用(超时):

// Modules imports and variable declarations here...

exports.handler = async () => 
  const hosts = (await marklogic.hosts.getHosts(taskServers, options) || []);
  const queueUrl = await aws.sqs.getQueueUrlByName(RESTART_QUEUE_NAME);
  const addToQueueResults = await aws.sqs.addMessages(queueURL, hosts);

  return 
    status: 200,
    body: addToQueueResults
  ;

这不起作用(超时):

// Modules imports and variable declarations here...

exports.handler = async () => 
  const hosts = (await marklogic.hosts.getHosts(taskServers, options) || []);
  const queueUrl = await aws.sqs.getQueueUrlByName('my-queue-name');
  const addToQueueResults = await aws.sqs.addMessages('http://queueurl.com', ['anything', 'in', 'here']); // Doesn't even need the queueUrl or hosts anymore

  return 
    status: 200,
    body: addToQueueResults
  ;

这行得通。它将在响应中返回我期望的主机对象:

// Modules imports and variable declarations here...

exports.handler = async () => 
  const hosts = (await marklogic.hosts.getHosts(taskServers, options) || []);

  return 
    status: 200,
    body: hosts 
  ;

这行得通。它将获取队列 url,然后将消息添加到我的 SQS 队列并返回 SQS 响应:

// Modules imports and variable declarations here...

exports.handler = async () => 
  const queueUrl = await aws.sqs.getQueueUrlByName(RESTART_QUEUE_NAME);
  const addToQueueResults = await aws.sqs.addMessages(queueUrl , ['anything', 'in', 'here']);

  return 
    status: 200,
    body: addToQueueResults
  ;

我尝试在 AWS Lambda function handler in Node.js 中实现异步处理程序,并查看了许多 AWS Lambda 执行故障排除文档。 marklogic 管理 API 默认在 8002 端口上运行,我认为 aws-sdk 模块使用 http/https (80/443),所以我不认为端口被占用。

我在这里错过了什么?

编辑 2:这与 AWS Lambda 如何处理承诺有关。我找不到太多关于此的信息。即使按照 AWS Lambda function handler in Node.js 中关于“异步处理程序”的说明,我也无法让它工作。无论有没有我的自定义 lambda 层,它都可以在本地完美运行。

Node.js 运行时:12.x(我之前没有提到)

这也不起作用(超时):

// Modules imports and variable declarations here...

exports.handler = async function (event) 
  const promise = function () 
      return new Promise(async function (resolve, reject) 
        try 
          const hosts = await marklogic.hosts.getHosts(taskServers, options) || [];
          const queueUrl = await aws.sqs.getQueueUrlByName(RESTART_QUEUE_NAME);
          const addToQueueResults = await aws.sqs.addMessages(queueUrl, hosts); 
          resolve(
            status: 200,
            body: addToQueueResults
          );
         catch (error) 
           reject(
             status: 500,
             error: error
           );
        
      );
  ;

  return promise(); // Throws error without constructor despite the AWS doc example

除非有人 AWS Lambda 天才之前在使用 Node.js 时遇到过类似的问题,否则我只会将其转换为 2 个 lambda 函数并使用 Step Functions 来处理它们。

【问题讨论】:

“不起作用”是什么意思?有什么例外吗?它会记录什么吗? 您是否在每次尝试/捕获主机、queueurl 和 addToQueueResults 后尝试额外的日志记录,以检查哪些成功以及发生超时的位置? @kichik 抱歉,我应该添加更多上下文。函数超时。每个操作只需要大约 0.5 秒即可运行,但仍会超时,最大超时时间为 30 秒。 @LeighMathieson 第一次尝试/捕获时超时。我只是不明白为什么。没有 sqs 代码它工作正常。没有 marklogic 代码,sqs 代码也能正常工作。 怎么初始化marklogic和sqs?这应该很重要。 【参考方案1】:

queueUrl 中有一个错字(我想不是这样,但值得一试!)

请运行:

// Custom lambda layer
const  marklogic, aws  = require('nodejs-layer-lib');

const  HOSTS, DOMAIN, PORT, USERNAME, PASSWORD, RESTART_QUEUE_NAME  = process.env;

const params = [
    'format=json'
];

const options = 
    port: PORT,
    params,
    httpOptions: 
        headers: 
            Authorization: `Basic $Buffer.from(`$USERNAME:$PASSWORD`).toString('base64')`
        ,
        method: 'GET'
    
;

const taskServers = (HOSTS.split(',') || []).map(host => 
    const _host = host.split(':');

    return 
        id: _host[0],
        name: `http://$_host[1].toLowerCase().$DOMAIN`
    ;
);

exports.handler = async () => 
    let hosts, queueUrl, addToQueueResults;

    try 
        hosts = (await marklogic.hosts.getHosts(taskServers, options) || []);
     catch (e)  console.error('hosts', e); 

    try 
        queueUrl = await aws.sqs.getQueueUrlByName(RESTART_QUEUE_NAME);
     catch (e)  console.error('queueUrl ', e); 

    try 
        addToQueueResults = await aws.sqs.addMessages(queueUrl, hosts);
     catch (e)  console.error('addToQueueResults ', e); 

    return 
        status: 200,
        body: JSON.stringify(addToQueueResults)
    ;
;

//保持相同的格式.. ^^

如果不走运 - 我的想法是,aws-sdk 已包含在 lambda 中,开箱即用。通过层额外要求它是不习惯的,尽管它可能看起来不像是在顶层导入的通过 marklogic,它可能被深深地捆绑在 marklogic 中,然后当您导入 AWS 并更改配置(在层中)时,它会覆盖它

让我们找出答案..:

第 1 步:

那么,你说的应该可以工作.. 如果我们忽略 AWS 导入,只导入 marklogic?

// Custom lambda layer
// const  marklogic, aws  = require('nodejs-layer-lib'); // ignoring AWS for now
const  marklogic  = require('nodejs-layer-lib');

const  HOSTS, DOMAIN, PORT, USERNAME, PASSWORD, RESTART_QUEUE_NAME  = process.env;

const params = [
    'format=json'
];

const options = 
    port: PORT,
    params,
    httpOptions: 
        headers: 
            Authorization: `Basic $Buffer.from(`$USERNAME:$PASSWORD`).toString('base64')`
        ,
        method: 'GET'
    
;

const taskServers = (HOSTS.split(',') || []).map(host => 
    const _host = host.split(':');

    return 
        id: _host[0],
        name: `http://$_host[1].toLowerCase().$DOMAIN`
    ;
);

exports.handler = async () => 
    // let hosts, queueUrl, addToQueueResults;
    let hosts;

    try 
        hosts = (await marklogic.hosts.getHosts(taskServers, options) || []);
        console.log('hosts => ', hosts);

        // queueUrl = await aws.sqs.getQueueUrlByName(RESTART_QUEUE_NAME);

        // addToQueueResults = await aws.sqs.addMessages(queueUrl, hosts);

        return 
            status: 200,
            body: JSON.stringify(hosts)
        ;
     catch (error) 
        console.log('error => ', error);

        throw error;
    
;

好的,如果可行的话..:

第 2 步(请设置 SQS 的区域以及 queueUrl 中的硬编码):

// Custom lambda layer
// const  marklogic, aws  = require('nodejs-layer-lib');
const  marklogic  = require('nodejs-layer-lib');

const AWS = require('aws-sdk');

AWS.config.update( region: 'eu-west-1' ); // Please set region accordingly
const sqs = new AWS.SQS( apiVersion: '2012-11-05' );

const  HOSTS, DOMAIN, PORT, USERNAME, PASSWORD, RESTART_QUEUE_NAME  = process.env;

const params = [
    'format=json'
];

const options = 
    port: PORT,
    params,
    httpOptions: 
        headers: 
            Authorization: `Basic $Buffer.from(`$USERNAME:$PASSWORD`).toString('base64')`
        ,
        method: 'GET'
    
;

const taskServers = (HOSTS.split(',') || []).map(host => 
    const _host = host.split(':');

    return 
        id: _host[0],
        name: `http://$_host[1].toLowerCase().$DOMAIN`
    ;
);

exports.handler = async () => 
    let hosts, addToQueueResults;

    try 
        hosts = (await marklogic.hosts.getHosts(taskServers, options) || []);
        console.log('hosts => ', hosts);

        const queueUrl = 'Please hard code the queueUrl for now';

        const sqsParams = 
            MessageBody: hosts,
            QueueUrl: queueUrl
        ;

        addToQueueResults = await sqs.sendMessage(sqsParams).promise();

        console.log('addToQueueResults => ', addToQueueResults);

        return 
            status: 200,
            body: JSON.stringify(addToQueueResults)
        ;
     catch (error) 
        console.log('error => ', error);

        throw error;
    
;

如果 .. 这不起作用.. 然后第 3 步 .. 将 marklogic 的要求移至 AWS 的要求以下,并在最后一个示例中设置区域.. (所以我们是任何深度嵌套的 marklogic AWS 逻辑不知道现在覆盖了您的 AWS 要求..) 重新运行它.. 手指交叉:-)

【讨论】:

这是个好主意。我实际上可能会更进一步,完全删除 lambda 层。然后,我可以确认该错误是否与图层本身有关。我会让你知道会发生什么。 任何更新@dj11223344 ..? 是的。对不起。我应该给你一个评论。不幸的是,您提供的答案不起作用。我又尝试了几件事。在这一点上,我几乎已经放弃了。我只是要使用一个阶梯函数来链接几个 lambda 函数。该代码在本地运行良好。所以它有一个 Lambda 特定的问题。

以上是关于异步代码独立工作,但不能一起工作。没有任何异常,只是超时的主要内容,如果未能解决你的问题,请参考以下文章

Django REST 权限类不能在 OR 中一起工作,而是按预期独立工作

为啥以下 jquery 可以在 jsfiddle 中工作,但不能在任何浏览器上工作? [关闭]

F# 线程中的取消标记

谷歌地图可以在模拟器上工作,但不能在 React 本机 APP 的 android 设备上工作

Discord bot命令随机停止与python一起工作?

有人能告诉我为啥这段代码似乎可以工作,但不能……拜托?