节点 8.10 + 请求导致 AWS lambda 跨越两个请求的结果

node 8.10 + Request causes AWS lambda to span result over two requests

已编辑以添加更多信息

当 运行 在 AWS Lambda 运行 中,相同版本的 Node 上的相同代码在本地工作正常时,我在使用任何依赖于 "request" 的库时遇到了重大问题。

本期推荐的所有方法我都试过了https://github.com/request/request/issues/2047

我还尝试了 AWS Lambda 论坛、亚马逊支持、Slack 频道和请求承诺回购。请求本身只是将查询定向到这里。

我不能在这里 post 一个完整的例子,因为我的函数有 18 个文件,8 个包,都有自己的子包。但是,它远低于 Lambda 的最大代码大小。 Shis 正是我在这个函数中 运行ning 的代码:

'PodcastInvocationIntent': function () {
        feedparser.parse("http://feeds.soundcloud.com/users/soundcloud:users:238643239/sounds.rss").then(items => {
            const now = new Date();
            console.log(`within feedparser and got item1  of ${items[0].title} at ${now}`);
        }).catch(err => {
            console.log(`Caught an error in checking - ${err}`);
        });
    },

我调用的函数只是调用一个有效的、快速响应的播客。注意:我可以通过 ask deploy -t lamba 来确保等于 "cold start"。

START RequestId: dcae5bc2-4883-11e8-a386-853cdfb729cc Version: $LATEST
2018-04-25T12:26:22.593Z    dcae5bc2-4883-11e8-a386-853cdfb729cc    in _MAINMENU_MODE and caught PodcastInvocationIntent
END RequestId: dcae5bc2-4883-11e8-a386-853cdfb729cc
REPORT RequestId: dcae5bc2-4883-11e8-a386-853cdfb729cc  Duration: 129.95 ms Billed Duration: 200 ms     Memory Size: 1024 MB    Max Memory Used: 48 MB  

如果我稍后调用它,我会得到第一个请求的其余部分。请注意,feedparser 结果的 RequestId 与第一次调用相同,结束于 853cdfb729cc,"brought forward" 到近一分钟后的请求 ID,即 171032bc3aa8

START RequestId: f6dcc8de-4883-11e8-be3e-171032bc3aa8 Version: $LATEST
2018-04-25T12:27:05.605Z    dcae5bc2-4883-11e8-a386-853cdfb729cc    within feedparser and got item1 of Episode 020 - Building Community in the Era of Voice at Wed Apr 25 2018 12:27:05 GMT+0000 (UTC)
2018-04-25T12:27:05.750Z    f6dcc8de-4883-11e8-be3e-171032bc3aa8    in _MAINMENU_MODE and caught PodcastInvocationIntent
END RequestId: f6dcc8de-4883-11e8-be3e-171032bc3aa8
REPORT RequestId: f6dcc8de-4883-11e8-be3e-171032bc3aa8  Duration: 327.94 ms Billed Duration: 400 ms     Memory Size: 1024 MB    Max Memory Used: 54 MB  

请注意,这是 将近一分钟后 - 我的 lambda 超时设置为 6 秒,我的请求超时设置为 3 秒,站点在 300 毫秒内响应。而且从服务器发送的header可以看出,正在记录的肯定是第一个请求。

另一件事 - 这是它第二次工作的一些请求摘要:

REPORT RequestId: 55fe3685-487f-11e8-9d8a-7f110e92019c Duration: 29.75 ms  Billed Duration: 100 ms  Memory Size: 1024 MB Max Memory Used: 55 MB < fail 
REPORT RequestId: 6b657de4-487f-11e8-b3d9-775cb704cd69 Duration: 119.94 ms Billed Duration: 200 ms  Memory Size: 1024 MB Max Memory Used: 55 MB < OK 

REPORT RequestId: 79c7e5ef-487f-11e8-a6be-039c7c5578d1 Duration: 18.75 ms  Billed Duration: 100 ms  Memory Size: 1024 MB Max Memory Used: 65 MB < fail 
REPORT RequestId: 95b42e1f-487f-11e8-863b-1bf45c029658 Duration: 122.49 ms Billed Duration: 200 ms  Memory Size: 1024 MB Max Memory Used: 65 MB < OK 

请注意,第一次请求在 18 或 29 毫秒时完成,但播客服务器的响应速度绝不会超过 55 毫秒(最多 300 毫秒)。 但需要明确的是,我已经在不同大小的不同服务器上尝试了多个播客。

(不知道为什么后两个大 10Mb - 相同的代码!)

这很有道理!有任何想法吗? 节点 8.10 请求 2.85.0 alexa-sdk 1.0.25,Lambda 上的备用内存负载,没有达到任何限制。

我已经尝试过 request、request-promise 和 feedparser-promised,并且都显示相同的症状。谢谢。

终于找到了答案,几乎是偶然的。复制代码示例的危险!

tl;dr this.emit(':saveState', true); 搞定请求库!

我有很多状态、状态处理程序和意图。每个意图都应该从任何状态横向可用。不能在每个州复制每个意图,所以...

在每个状态下,我都有该状态的特定处理程序,未处理的会拾取其他所有内容并将其反弹到 genericIntentHandler。然后将其转发到正确的状态和处理程序。像这样:

 'Unhandled': function () {
            console.log(`in ${this.attributes.STATE} and caught ${this.event.request.intent.name}`);
            GIH.genericIntentHandlers.call(this);
        },

然后分别:

function genericIntentHandlers() {
    if (this.event.request.type === 'IntentRequest') {
        const intentName = this.event.request.intent.name;
        console.log(`in genericIntentHandlers redirect function with ${intentName}`);
        if (genericHandlers.hasOwnProperty(intentName)) { // true
            genericHandlers[intentName].call(this);
        } else {
            this.response.speak("I didn't understand that. Try main main or help if you're stuck.").listen("reprompt");
            this.emit(':responseReady');
        }
    } else {
        console.log(`in genericIntentHandlers redirect function with LaunchRequest`);
        genericHandlers['LaunchRequest'].call(this);
    }
}


const genericHandlers = {
    'PodcastInvocationIntent': function () {
        this.handler.state = constants.states.POD_MODE;
        // this.emit(':saveState', true); // this is what was screwing it!
        this.emitWithState('PodcastInvocationIntent');
    }
// plus every single state that exists anywhere. Like a lookup table.
}

并在 POD_MODE 状态处理程序中:

'PodcastInvocationIntent': function () {
            feedparser.parse("http://feeds.soundcloud.com/users/soundcloud:users:238643239/sounds.rss").then(items => {
                const now = new Date();
                console.log(`within feedparser and got item1  of ${items[0].title} at ${now}`);
                //console.log(`within feedparser and got items of ${JSON.stringify(items)}`);
            }).catch(err => {
                console.log(`Caught an error in checking - ${err}`);
            });
        },

所以,澄清一下,并经过多次重新测试:

在正常的事件过程中,发出 this.emit(':saveState', true); 没有任何区别,除非使用任何使用请求库的库,在这种情况下,它似乎将请求“拆分”到两个 lambda 实例上。是的,我知道。疯狂。

这留下了两个问题:为什么?而且,这肯定会使文档的这一点不正确吗?

When any of the response events are emitted :ask, :tell, :askWithCard, etc. The lambda context.succeed() method is called if the developer doesn't pass in callback function, which immediately stops processing of any further background tasks. Any asynchronous jobs that are still incomplete will not be completed and any lines of code below the response emit statement will not be executed. This is not the case for non responding events like :saveState.

那么如果它是一个无响应事件,它为什么会干扰?

无论如何,正如他们所说,就是这样。一周后我再也回不来了,但非常感谢一路上帮助过我的人。