Скрипт установки модуля node-sass не завершается, когда npp запускается установкой Ruben's popen3.

ОБНОВЛЕНИЕ 3: Эта проблема, кажется, является частью установки модуля node-sass. Многожильный процесс имеет рабочий каталог ./node_modules/node-sass и его командная строка scripts/install.js разрешается в файл внутри модуля. Более того, последняя строка вывода, которая достигает консоли, соответствует строке вывода node-sass ' scripts/install.js:

if (cachedBinary) {
    console.log('Cached binary found at', cachedBinary);
    fs.createReadStream(cachedBinary).pipe(fs.createWriteStream(binaryPath));
    return;
}

Этот код не имеет проблем при запуске из командной строки (т. Е. Просто npm install в командной строке с пробелом node_modules каталог), но когда npm install запускается через popen3 кажется, что поток .pipe звоните сюда блоками бесконечно.

Это головная боль для меня на данный момент...

Если I ^C терминал, где Ruby запустил эти дочерние процессы, то прерывание переходит в мошеннический процесс и вызывает его завершение. Однако принудительное закрытие всех каналов (или просто завершение родительского процесса) не приводит к мошенничеству. node.exe выходить.

Я обдумывал альтернативную версию popen3 который явно ожидает дочерний процесс, а не просто неявно ожидает завершения всех потоков, но, хотя это и позволяет вызывающей стороне продолжаться правильно, мошеннический дочерний процесс все еще зависает и будет мешать последующим вызовам, удерживая открытая ручка к ./node_modules/node-sass каталог.

ОБНОВЛЕНИЕ 4: я открыл этот отчет об ошибке с node-sass проект: https://github.com/sass/node-sass/issues/2459


ОБНОВЛЕНИЕ: Я почти уверен, что это на самом деле проблема с Node. Я выследил основную причину зависания, и именно через сложное дерево дочерних процессов npm install в конечном итоге оставляет за собой экземпляр node.exe который просто сидит там, по-видимому, на неопределенный срок, ничего не делая, сохраняя stdout а также stderr Трубы унаследованные открыты.

Итак, это оставляет новые вопросы:

  1. Есть ли способ заставить Node не оставлять после себя процесс отставания после npm install завершается?
  2. Есть ли способ явно ждать прямого дочернего процесса popen3 выйти, вместо того чтобы ждать окончания потоков, а затем, возможно, закрыть потоки со стороны прослушивания, чтобы завершить потоки, накачивающие выход?

ОБНОВЛЕНИЕ 2: я воспроизвел проблему с этим минималистским кодом:

Open3::popen3 "npm install" do |stdin, stdout, stderr, thr|
  stdin.close
  stdout.each_line { |l| puts l }
end

С этим кодом, жулик node.exe процесс (командная строка: scripts/install.js бродит после npm install завершается. Завершение процесса разблокирует popen3 вызов (вызывая stdout чтобы положить конец, поэтому each_line цикл завершается), и ^Cing код Ruby (при запуске в окне IRB) вызывает мошенничество node.exe завершить (после строки в выводе консоли: => #<IO:(closed)>).

Это происходит только тогда, когда процесс проходит popen3; идентичный npm install из CMD подсказка выходит нормально.


Оригинальный вопрос:

У меня проблема с popen3 в сценарии Ruby. Он висит, но я уверен, что это не обычный кандидат. Я обновил свой звонок popen3 с тоннами аннотаций, чтобы я мог видеть в выводе консоли, что происходит. Вот как я звоню:

  command_output_lines = []
  lock = Mutex.new

  exit_code = nil

  Logger.log("[MAIN] beginning popen3 block")

  Open3.popen3(command_w_params) do |stdin, stdout, stderr, thr|
    Logger.log("[MAIN] closing stdin stream")

    stdin.close

    Logger.log("[MAIN] starting [STDOUT]")

    stdout_thread = Thread.new do
      Logger.log("[STDOUT] started")

      begin
        stdout.each_line do |stdout_line|
          Logger.log("[STDOUT] got a line, acquiring lock")

          lock.synchronize do
            command_output_lines <<= stdout_line
            Logger.log(stdout_line)
          end

          Logger.log("[STDOUT] lock released")
        end
      rescue Exception => e
        Logger.log("[STDOUT] exception: #{e}")
      end

      Logger.log("[STDOUT] exiting")
    end

    Logger.log("[MAIN] starting [STDERR]")

    stderr_thread = Thread.new do
      Logger.log("[STDERR] started")

      begin
        stderr.each_line do |stderr_line|
          Logger.log("[STDERR] got a line, acquiring lock")

          lock.synchronize do
            command_output_lines <<= "[STDERR] " + stderr_line
            Logger.warn(stderr_line)
          end

          Logger.log("[STDERR] lock released")
        end
      rescue Exception => e
        Logger.log("[STDERR] exception: #{e}")
      end

      Logger.log("[STDERR] exiting")
    end

    Logger.log("[MAIN] joining to [STDOUT]")
    stdout_thread.join
    Logger.log("[MAIN] joining to [STDERR]")
    stderr_thread.join

    Logger.log("[MAIN] threads joined, reading exit status")

    exit_code = thr.value.exitstatus
  end

  Logger.log("[MAIN] popen3 block completed")

(Не бери в голову, что именно Logger.log является; просто знайте, что он отправляет вывод на консоль.)

Где я вижу проблему, command_w_params равно npm install и этот код выполняется в контексте bundle exec rake TaskName,

Когда он достигает этого кода, я вижу следующий вывод консоли:

[MAIN] beginning popen3 block
[MAIN] closing stdin stream
[MAIN] starting [STDOUT]
[MAIN] starting [STDERR]
[MAIN] joining to [STDOUT]
[STDOUT] started
[STDERR] started
[STDOUT] got a line, acquiring lock

[STDOUT] lock released
[STDOUT] got a line, acquiring lock
> node-sass@4.9.2 install C:\Users\Jonathan Gilbert\RepositoryName\ProjectName\node_modules\node-sass
[STDOUT] lock released
[STDOUT] got a line, acquiring lock
> node scripts/install.js
[STDOUT] lock released
[STDOUT] got a line, acquiring lock

[STDOUT] lock released
[STDOUT] got a line, acquiring lock
Cached binary found at C:\Users\Jonathan Gilbert\AppData\Roaming\npm-cache\node- sass\4.9.2\win32-x64-57_binding.node
[STDOUT] lock released

... а потом просто зависает. На данный момент я вижу в Process Explorer, что дочерний процесс завершился. Там ничего не осталось, кроме ruby.exe, но он просто сидит там бесконечно, пока не будет явно отменен. Два потока все еще работают, указывая, что stdout а также stderr потоки еще не сообщили о завершении потока.

Теперь, часто, когда люди имеют проблемы с popen3 это потому, что они не читают оба stdout а также stderr одновременно, и тот или другой заполняет свой конвейерный буфер, в то время как родительский процесс обращает внимание только на другой. Но мой код использует отдельные потоки и держит пустые буферы канала.

Еще одна проблема, которую я видел, заключается в том, что дочерний процесс может зависать в ожидании stdin быть закрытым, но в этом случае:

  • stdin закрывается.
  • Дочерний процесс даже не существует.

Кто-нибудь распознает эти симптомы? Почему stdout а также stderr потоки не достигают конца потока при выходе из дочернего процесса??

0 ответов

Другие вопросы по тегам