【问题标题】:Why does the Pry shell timeout so quickly in Phoenix/cowboy? (shell process exited with reason: shutdown)为什么 Pry shell 在 Phoenix/cowboy 中超时如此之快? (shell进程退出原因:关机)
【发布时间】:2021-04-04 20:18:22
【问题描述】:

当我使用 IEx.pry 或断点(通过 :int.break())时,交互式 shell 死得太快,我只有大约 10 秒的时间失去会话:

** (EXIT from #PID<0.606.0>) shell process exited with reason: shutdown

10 秒不足以在 shell/调试器中高效地调试我的代码。我最好的猜测是 :supervisor.child_spec 中有一个默认超时,我需要覆盖它,但我不是 100% 确定。

这是我迄今为止尝试过的(以及为什么它们到目前为止还没有奏效):

  • 将 child_specs 中的 :shutdown parameter 增加到 :infinity 到 MyApp.Application 中的 Supervisor.start_link()
  • 更新了cowboy timeouts(idle_timeout、linger_timeout、request_timeout、shutdown_timeout),因为 Observer 指出我的请求是一个牛仔进程。不过,我认为这不太可能是牛仔。如果默认是 60s,我什至没有接近 60s。
  • 我没有使用 IEx.pry,而是尝试使用调试器(通过 :ni.break
  • 只是注意到我不能使用mix test --trace,它将超时设置为:infinity。由于我正在尝试调试非测试端点操作,因此此标志无济于事。

人们如何使用调试器/IEx.pry? (我来自 Ruby/JS 世界,所以我希望有一些时间来检查变量。)人们只是没有像我一样遇到 10 秒超时吗?或者是否有一些我因故障排除需要而缺少的常用配置?

application.ex 中我的主管/子配置:

注意shutdown: :infinity 配置。

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      MyApp.Repo,
      {MyApp.Web.Endpoint, [shutdown: :infinity]},
      {Phoenix.PubSub, [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2]},
      {MyApp.Middleware.Ets.AnEtsThing, [name: MyApp.Middleware.Ets.AnEtsThing, table_name: :my_app_config_2]},
    ]
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end

  def config_change(changed, _new, removed) do
    MyApp.Web.Endpoint.config_change(changed, removed)
    :ok
  end
end

我在 dev.exs 中的牛仔配置

config :my_app, MyApp.Web.Endpoint,
  http: [
    port: 4000,
    protocol_options: [
      request_timeout: 100_000_000,
      shutdown_timeout: 100_000_000,
      idle_timeout: 100_000_000,
      linger_timeout: 100_000_000,
    ]
  ]

Cowboy 配置的控制台检查

这只是为了确认我在正确的位置配置了 Cowboy。我确认切换端口确实会影响端口。

iex(4)> MyApp.Web.Endpoint.config(:http)
[
  port: 4001,
  protocol_options: [
    request_timeout: 100000000,
    shutdown_timeout: 100000000,
    idle_timeout: 100000000,
    linger_timeout: 100000000
  ]
]

这是我通过运行 iex -S mix phx.server 在 IEX 控制台中看到的:

请注意,没有堆栈跟踪可以告诉我是什么杀死了我的 pry 会话。

Interactive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)
Request to pry #PID<0.718.0> at MyApp.Foo.foo/3 (lib/my_app/foo.ex:16)

   14: 
   15:   def foo(_parent, _args, %{context: %{bar: bar}}) do
   16:     require IEx; IEx.pry
   17: 
   18:     some_code()

Allow? [Yn] <=== I type "Enter"
        
Interactive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)
pry(1)> DateTime.utc_now <=== I type this to show when the pry session starts
~U[2020-12-28 06:18:27.861251Z]
** (EXIT from #PID<0.718.0>) shell process exited with reason: shutdown
        
...
        
Interactive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)
pry(1)> DateTime.utc_now
~U[2020-12-28 06:18:40.420951Z] <== ~13 seconds, pry session dies

【问题讨论】:

  • 请分享完整的堆栈跟踪。
  • @AlekseiMatiushkin 我用控制台输出更新了原始帖子,但不幸的是没有任何堆栈跟踪!这就是我难过的部分原因。
  • 我对 elixir/pry 了解不多,但是 shell 死掉了,因为它与进程相关联:因为进程以 shutdown 退出(可能是没有堆栈跟踪的原因),它发出相同的信号,因此 shell 以shutdown 退出。进程可能会收到来自多个来源的shutdown信号,您可以查看进程中的origin trapping信号并跟随链。

标签: erlang timeout elixir phoenix-framework cowboy


【解决方案1】:

我发现了问题:问题在于我在一个单独的 JS 项目中设置了 10 秒超时。(哈哈糟糕!)我最终使用 Erlang Observer 在 @ 添加了详细跟踪987654325@ 并找到有关正在发送的特定 Cowboy 错误的更多内部细节,这使我意识到它是从 JS 发起的。

解释JS(即客户端)超时如何影响cowboy/Phoenix调试

客户端会在 10 秒后反复关闭 HTTP 连接,导致 Cowboy(Phoenix 的构建基础)终止其 HTTP 流处理程序,进而终止 Phoenix IEx.pry 会话。

这意味着我增加 Cowboy 超时配置的尝试不会改变 kill 行为。我的超时正在更改,但没有被触发。

我如何通过 Erlang 的 :observer 解决 Cowboy 超时问题

虽然我的 JS 问题是特定于项目的,但您可能需要从 Phoenix 应用程序中深入研究 Cowboy 的较低级别。这些

  1. 运行 Phoenix 应用程序iex -S mix phx.server
  2. 运行:observer.start() 启动观察者界面
  3. 单击Applications 选项卡,查找我的Phoenix 端点(如Elixir.MyApp.Web.Endpoint
  4. 右键单击其子项,单击每个子项的 Dictionary 选项卡以查找具有 '$initial_call'cowboy_clear 的选项卡(它嵌套在 MyApp.Web.Endpoint 的 3 层深处)
  5. (在这里我能够确认我触发的 Pry 断点是来自此 cowboy_clear 节点的后代,类似于:self |&gt; Process.info |&gt; Keyword.get(:dictionary) |&gt; Keyword.get(:"$ancestors")。)
  6. 右键单击cowboy_clear 并选择“跟踪进程树” - 我选择了所有选项。
  7. 将选项卡更改为“跟踪概述”,选择 pid,然后单击“开始跟踪”
  8. 等待牛仔死,然后将跟踪保存到文本文件中
  9. 搜索“退出”、“关闭”或类似内容
  10. 就我而言,我找到了20:57:13:358740 (&lt;0.5984.0&gt;) exit {shutdown,{socket_error,closed,'The socket has been closed.'}}
  11. 此时,我猜是 JS b/c Cowboy 似乎不是触发请求关闭的那个

额外思考:理论上我可以通过在 GraphiQL 或 Postman 中运行我的请求来节省大量时间,因为那里不存在超时。

有用的资源

【讨论】:

    猜你喜欢
    • 2010-11-30
    • 1970-01-01
    • 2020-10-22
    • 2012-04-19
    • 1970-01-01
    • 2021-08-13
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    相关资源
    最近更新 更多