【问题标题】: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?这应该很重要。

标签: javascript node.js amazon-web-services aws-lambda async-await


【解决方案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 特定的问题。
猜你喜欢
  • 2021-02-21
  • 2020-01-20
  • 2021-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-21
  • 1970-01-01
  • 2023-03-31
相关资源
最近更新 更多