Heroku会截断HTTP响应吗?


78

我在Heroku Cedar dyno上运行Flask / Gunicorn Python应用程序。该应用返回JSON responses给客户(实际上是个API server)。

客户端有时会收到0字节的响应。但是,不是我退还他们。这是我的应用程序日志的一个片段:

3月14日13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 app [web.1] [2013-03-14 13:13:31 UTC] 10.104.41.136 apisrv-api_get_credits_balance():session_token = [MASKED ]

上面的第一行是我开始处理请求的过程。

3月14日13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 app [web.1] [2013-03-14 13:13:31 UTC] 10.104.41.136 apisrv 1252148511 api_get_credits_balance():返回[{ credits_balance':0}]

第二行是我返回一个值(到Flask -这是Flask的“ Response”对象)。

3月14日13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 app [web.1]“ 10.104.41.136--[14 / Mar / 2013:13:13:31]” POST / get_credits_balance?session_token =屏蔽HTTP / 1.1“ 200 22”-“” Appcelerator Titanium / 3.0.0.GA(iPhone / 6.1.2; iPhone OS; en_US;)“

第三行是Gnicorn,其中您可以看到Gunicorn的状态为200,HTTP正文为22字节200 22

但是,客户端获得了0个字节。这是Heroku路由器日志:

3月14日13:13:30 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 heroku [router] at = info method = POST path = / get_credits_balance?session_token = MASKED host = matchspot-apisrv.herokuapp.com fwd =“ 66.87。 116.128“ dyno = web.1队列= 0等待= 0ms连接= 1ms服务= 19ms状态= 200字节= 0

为什么Gunicorn返回22个字节,但是Heroku看到0,并确实将0个字节传回给客户端?这是Heroku的错误吗?


1
您是否注意到,heroku时间戳在您的过程时间戳之前?您使用gevent吗?我认为同步有问题。
Tigra

2
但是,时间戳表示1秒的差异,而不是1 1ms ...我没有使用heroku,所以这只是建议。1ms和1999ms都可以给您1秒的时间戳差异。服务19毫秒也太低,无法在云服务上实现。所以我的意思是,可能有某种超时和超时而不是错误,但是heroku服务于空页面。这个建议是长远的建议,但也许您应该效仿长远的要求,看看会发生什么
Tigra

9
当您与他们联系时(出于好奇),Heroku有多有用?
orokusaki 2013年

6
到目前为止还不是很清楚。我在10天前与他们取得了联系,并被告知Python团队会首先查看它,如果他们不能帮我,那么路由团队将来看看。5天后,我被告知Python人员已经将此问题传递给了路由人员,今天我收到了来自“路由人员”的电子邮件,称他无法重新创建并要求提供更多信息。因此,是的,他们正在经历正确的过程,但这是永远的过程。
Nitzan于2013年

1
小更新:尚未解决。我一直在Heroku的支持下来回交流,现在我能收集到的最好的信息是,他们并没有因为“它就在你身边”而解雇了我,并且正在尝试编写一种工具来捕获tcpdump的应用流量,用于“调试此类情况”。
Nitzan于2013年

Answers:


1

我知道这里可能会给我一点麻烦,但还有另一种选择。

我们知道在运输过程中会不时发生错误,我们现在无法采取行动来解决问题。如果仅提供API,则停止阅读,但是如果您也编写客户端,请继续。

该错误是已知情况,也是已知原因。返回值为空的结果表示出了点问题。但是,该值是可用的,并且可以进行获取,计算等操作……作为开发人员,我的本能是将空结果视为HTTP错误并请求重新发送数据。然后,您可以跟踪重新发送请求,并查看这种情况发生的频率。

我建议(尽管您也像我这样考虑开发人员,这也让我感到震惊)建议您对请求进行计数并设置合理的值,以响应用户的“网络错误”。我的本能是立即重试,然后稍等一会再重试。

根据您的描述,第一次重试可能会正确提取数据。当然,这可能意味着将较旧的请求保留在缓存中几分钟,或者再次运行该请求,这取决于看起来最合适的请求。

这样还可以解决许多其他点对点网络错误,即使面对连接问题,也可以使应用程序更加强大。

我知道我们作为开发人员的本能是要修复已知的故障,但是有时朝着即使有故障也能够运行的系统工作会更好。那就是说记录错误和问题并尝试修复它们永远不会受到伤害。


实际上,这不是一个不好的评论(尽管可能应该在评论中而不是在答案中),并且不要以为我没有考虑过……问题是客户端无法再次发出请求,因为该请求可能具有服务器端的副作用(例如,第二次转账)。解决方案是让客户端发出request_id,并让服务器保留“最近60秒内已提供了哪个request_id”的列表。当客户端收到一个200响应(包含0个字节的正文)时,它会重新发出具有相同ID的请求,并且服务器不会重新执行(续)
Nitzan Shaked

(而不是)整个事情。但是,这太丑了,我选择不执行。
尼肯(Nitzan)

我几乎不是缓存的初学者,但是在我看来:发送随机字符串作为请求的一部分,然后缓存结果。当您使用相同的随机字符串重新发送请求时,自然会获取缓存的结果(相同的内容,相同的源...),但是当您发送合法的新请求时,您将拥有一个新的随机字符串,因此不会被缓存结果。
Narfanator
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.