Проверьте, почему ruby ​​script зависает

Иногда мои спецификации могут просто зависать, и я должен убить соответствующий рубиновый процесс. Это довольно часто, когда я запускаю спецификации интеграции, написанные с помощью драйвера capybara и webkit.

Можно ли проверить данный рубиновый процесс и посмотреть, где он висит? Какой метод, операция, файл, номер строки и т.д.

Ответ 1

TL;DR

Используйте 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 script с помощью библиотеки отладки.

Если script выполняется из оболочки, это может быть достигнуто путем изменения первой строки (shebang) script в:

#!/usr/bin/env ruby -rdebug

или запустив его как:

ruby -rdebug my_script.rb

Как только отладчик загружен, вы можете настроить некоторые точки останова или просто запустить приложение, набрав c, чтобы продолжить выполнение.

Затем отладчик автоматически разбивается на любые Исключения (такие как Ctrl+C) или контрольные точки (например, строки, которые состоят из debugger).

Затем каждый раз, когда отображается консоль отладчика, вы можете выбирать между:

  • c для продолжения (к следующему исключению, точке останова или строке с помощью: debugger),
  • n для следующей строки,
  • w/where для отображения стека кадров/вызовов,
  • l Чтобы показать текущий код,
  • cat, чтобы показать контрольные точки.
  • h для получения дополнительной справки.

Смотрите также: Отладка с ruby-debug, Ключевые ярлыки для рубинового отладочного камня.

Недостатком этого метода является то, что нет волшебной кнопки для подбора отладчика по требованию, кроме создания исключения в script, а также для отображения другого блока кода, а не зависания.

Вот несколько других идей:

  • Добавьте оператор debugger в свой код, поднимите отладчик и пошаговый шаг.
  • Используйте Pry отладчик (см.: GitHub).

    Установить через: gem install pry, выполнить как: pry или добавить как require 'pry'.

  • Попробуйте lldb (который должен заменить gdb), который может подключаться к текущему запуску процесса.

    Пример (замените PID на ваш идентификатор процесса):

    $ 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 ​​ script (на его tty):

    echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -f ruby)
    
  • В качестве альтернативы используйте gdb (вы можете расширить его: gdb.rb, который может показать вам объекты ruby).

    • Установить через: sudo apt-get install gdb python-dev ncurses-dev && gem install gdb.rb
    • В Unix/OS X нажмите Ctrl+T, чтобы проверить PID и что делать (или проверить через ps wuax | grep ruby).
    • Присоедините к процессу через: gdb -p PID.

    См. также: с помощью gdb для проверки зависающего рубинового процесса, Обертка GDB для Ruby и Проверка реального процесса Ruby.

  • Другие библиотеки/инструменты, которые могут помочь включить: debugger, crash-watch, memprof, rack-perftools_profiler.

Если ничего не помогает, вы можете просто попробовать: strace (Linux)/dtruss (OS X) со следующим синтаксисом:

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

Или ltrace, который может отслеживать вызовы библиотеки, а не системные вызовы strace.

Если вы считаете, что это проблема сети, используйте tcpdump.

См. также:

Ответ 2

У меня была и эта проблема, и проследил ее до виджета Javascript ShareThis на определенной странице. Вы можете использовать или не использовать это, но реальная проблема, возможно, связана с тем, что что-то на странице вызывает внешний запрос, который никогда не заканчивается. 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?) Вокруг этого кода, и вуаля, я в бизнесе. Его дерьмовое обходное решение, чтобы приложить условные условия для тестовых сред в вашу кодовую базу... но это заставило меня перейти от этой глупой проблемы...

Надеюсь, что это поможет.