8

有时我的规范可能会挂起,我必须终止相应的 ruby​​ 进程。当我运行使用 capybara 和 webkit 驱动程序编写的集成规范时,这很常见。

是否可以检查给定的 ruby​​ 进程并查看它挂在哪里?哪个方法、操作、文件、行号等。

4

2 回答 2

11

tl;博士

使用gdb(例如 Linux):

  • echo 'call (void)rb_backtrace()' | gdb -p $(pgrep -f ruby)

或使用lldb(例如 OS X):

  • echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -f ruby)

您可以使用调试库来调试 Ruby 脚本。

如果脚本是从 shell 执行的,这可以通过将脚本的第一行 ( shebang ) 更改为:

#!/usr/bin/env ruby -rdebug

或将其运行为:

ruby -rdebug my_script.rb

加载调试器后,您可以设置一些断点,也可以通过键入c来运行应用程序以继续执行。

然后调试器会自动中断任何异常(例如Ctrl+C)或断点(例如包含 的行debugger)。

然后每次显示调试器控制台时,您可以选择:

  • c继续(到下一个异常、断点或行:)debugger
  • n对于下一行,
  • w/where显示帧/调用堆栈,
  • l显示当前代码,
  • cat显示捕捉点。
  • h更多帮助。

另请参阅:使用 ruby​​-debug 进行调试ruby-debug gem 的快捷键

这种方法的缺点是没有魔术按钮来按需启动调试器,除了在脚本中引发异常之外,它将显示不同的代码块而不是挂起一个。

这里有一些其他的想法:

  • debugger语句添加到您的代码中,启动调试器并逐步进行。
  • 请改用Pry调试器(请参阅:GitHub)。

    通过安装:gem install pry,运行为:pry或添加为require 'pry'

  • 尝试可以附加到当前正在运行的进程的lldb调试器(旨在替换)。gdb

    示例(替换PID为您的进程 ID):

    $ lldb -p PID
    (lldb) bt all
    * thread #1: tid = 0x11d68a, 0x00007fff86c71716 libsystem_kernel.dylib`__psynch_cvwait + 10
      * frame #0: 0x00007fff86c71716 libsystem_kernel.dylib`__psynch_cvwait + 10
        frame #1: 0x00007fff838a9c3b libsystem_pthread.dylib`_pthread_cond_wait + 727
        frame #2: 0x0000000100241aad libruby.2.0.0.dylib`native_cond_wait + 29
    

    另一个显示实时运行 ruby​​ 脚本的回溯示例(在其 tty 上):

    echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -f ruby)
    
  • 或者使用gdb(您可以通过以下方式扩展它:gdb.rb可以向您显示 ruby​​ 对象)。

    1. 通过以下方式安装:sudo apt-get install gdb python-dev ncurses-dev && gem install gdb.rb
    2. 在 Unix/OS X 上,按下Ctrl+T挂起进程以检查 PID 和正在做什么(或通过 检查ps wuax | grep ruby)。
    3. 通过以下方式附加到该过程:gdb -p PID

    另请参阅:使用 gdb 检查挂起的 Ruby 进程、 Ruby 的GDB 包装器检查实时 Ruby 进程

  • 其他可以提供帮助的库/工具包括:debuggercrash-watchmemprofrack-perftools_profiler

如果没有任何帮助,您可以简单地尝试:strace(Linux) / dtruss(OS X) 使用以下语法:

sudo strace -fp <PID>
sudo dtruss -fp <PID>

或者ltrace可以跟踪库调用而不是strace系统调用。

如果您认为这是网络问题,请使用tcpdump.

也可以看看:

于 2015-08-01T20:04:06.213 回答
1

我也遇到了这个问题,并将其追溯到特定页面上的 ShareThis javascript 小部件。您可能会或可能不会使用它,但真正的问题可能是它挂起,因为页面上的某些东西导致了一个永远不会完成的外部请求。Capybara-webkit 会知道原始请求,但是如果这段代码本身发出请求,capybara-webkit 将永远不会知道它,如果最后一个请求挂起,说等待响应,capybara-webkit 也会...

对您来说,使用 webkit-debug 运行测试并查看发出的最后一个请求。对我来说,我看到了以下内容:

    1 requests remaining 
    Page finished with true 
    Received 200 from "http://w.sharethis.com/share4x/js/st.60709d5fdf0c137e879e64f41b8a6606.js" 
    0 requests remaining 
    Started request to "http://w.sharethis.com/share4x/css/share.470030190b6a6bdc89365fcc74d3bf55.css" 
    Received 200 from "http://w.sharethis.com/share4x/css/share.470030190b6a6bdc89365fcc74d3bf55.css" 
    0 requests remaining 

这让我在我的代码库中搜索 ShareThis。我在该代码周围放置了一个 if(Rails.env.test?) 块,瞧,我在做生意。这是一个糟糕的解决方法,必须将测试环境的条件放入您的代码库中......但它让我从这个愚蠢的问题中继续前进......

希望这可以帮助。

于 2012-11-20T05:45:23.833 回答