为什么 Pry shell 在 Phoenix/cowboy 中超时得这么快?(shell进程退出原因:shutdown)

mon*_*ner 5 erlang timeout elixir cowboy phoenix-framework

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

\n

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

\n

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

\n

这是我到目前为止尝试过的(以及为什么他们到目前为止还没有工作):

\n
    \n
  • 将MyApp.Application 中Supervisor.start_link()的 child_specs 中的:shutdown 参数增加为 :infinity。
  • \n
  • 更新了牛仔超时(idle_timeout、linger_timeout、request_timeout、shutdown_timeout),因为观察者表明我的请求是牛仔进程。不过,我不认为\xe2\x80\x99很可能\xe2\x80\x99是牛仔。如果默认为 60 秒,则 I\xe2\x80\x99m 甚至还没有接近 60 秒。
  • \n
  • 我没有使用 IEx.pry,而是尝试使用调试器(通过:ni.break
  • \n
  • 只是注意到我可以\xe2\x80\x99t 使用mix test --trace,它将超时设置为:无穷大。由于我\xe2\x80\x99m 尝试调试非测试端点操作,因此此标志不会有帮助。
  • \n
\n

人们如何使用调试器/IEx.pry?(我来自 Ruby/JS 世界,所以我喜欢有一些时间来检查变量。)人们是否没有像我一样遇到 10 秒超时?或者我\xe2\x80\x99m 是否缺少一些常见配置来满足我的故障排除需求?

\n

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

\n

注意shutdown: :infinity配置。

\n
defmodule MyApp.Application do\n  use Application\n\n  def start(_type, _args) do\n    children = [\n      MyApp.Repo,\n      {MyApp.Web.Endpoint, [shutdown: :infinity]},\n      {Phoenix.PubSub, [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2]},\n      {MyApp.Middleware.Ets.AnEtsThing, [name: MyApp.Middleware.Ets.AnEtsThing, table_name: :my_app_config_2]},\n    ]\n    opts = [strategy: :one_for_one, name: MyApp.Supervisor]\n    Supervisor.start_link(children, opts)\n  end\n\n  def config_change(changed, _new, removed) do\n    MyApp.Web.Endpoint.config_change(changed, removed)\n    :ok\n  end\nend\n
Run Code Online (Sandbox Code Playgroud)\n

我在 dev.exs 中的牛仔配置

\n
config :my_app, MyApp.Web.Endpoint,\n  http: [\n    port: 4000,\n    protocol_options: [\n      request_timeout: 100_000_000,\n      shutdown_timeout: 100_000_000,\n      idle_timeout: 100_000_000,\n      linger_timeout: 100_000_000,\n    ]\n  ]\n
Run Code Online (Sandbox Code Playgroud)\n

Cowboy 配置的控制台检查

\n

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

\n
iex(4)> MyApp.Web.Endpoint.config(:http)\n[\n  port: 4001,\n  protocol_options: [\n    request_timeout: 100000000,\n    shutdown_timeout: 100000000,\n    idle_timeout: 100000000,\n    linger_timeout: 100000000\n  ]\n]\n
Run Code Online (Sandbox Code Playgroud)\n

这是我通过运行以下命令在 IEX 控制台中看到的内容iex -S mix phx.server

\n

请注意,没有堆栈跟踪告诉我是什么终止了我的窥探会话。

\n
Interactive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)\nRequest to pry #PID<0.718.0> at MyApp.Foo.foo/3 (lib/my_app/foo.ex:16)\n\n   14: \n   15:   def foo(_parent, _args, %{context: %{bar: bar}}) do\n   16:     require IEx; IEx.pry\n   17: \n   18:     some_code()\n\nAllow? [Yn] <=== I type "Enter"\n        \nInteractive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)\npry(1)> DateTime.utc_now <=== I type this to show when the pry session starts\n~U[2020-12-28 06:18:27.861251Z]\n** (EXIT from #PID<0.718.0>) shell process exited with reason: shutdown\n        \n...\n        \nInteractive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)\npry(1)> DateTime.utc_now\n~U[2020-12-28 06:18:40.420951Z] <== ~13 seconds, pry session dies\n
Run Code Online (Sandbox Code Playgroud)\n

mon*_*ner 1

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

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

CLIENT 将在 10 秒后重复关闭 HTTP 连接,导致 Cowboy(Phoenix 构建于其上)终止其 HTTP 流处理程序,这反过来又会终止 Phoenix 会话IEx.pry

这意味着我尝试增加牛仔超时配置不会改变杀死行为。我的超时被更改但没有被触发。

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

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

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

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

有用的资源