Скрипт установки модуля 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
Трубы унаследованные открыты.
Итак, это оставляет новые вопросы:
- Есть ли способ заставить Node не оставлять после себя процесс отставания после
npm install
завершается? - Есть ли способ явно ждать прямого дочернего процесса
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
потоки не достигают конца потока при выходе из дочернего процесса??