From 537736f519d4c34aba76580b93af5eb9530d6949 Mon Sep 17 00:00:00 2001 From: Masahiro Nakagawa Date: Tue, 15 Oct 2019 16:15:26 +0900 Subject: [PATCH] Merge pull request #2649 from fluent/fix-child_process-stderr child_process helper: fix stderr blocking for discard case. fix #2609 Signed-off-by: Masahiro Nakagawa --- lib/fluent/plugin_helper/child_process.rb | 5 +-- test/plugin_helper/test_child_process.rb | 37 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/fluent/plugin_helper/child_process.rb b/lib/fluent/plugin_helper/child_process.rb index 437c435c30..9967097c31 100644 --- a/lib/fluent/plugin_helper/child_process.rb +++ b/lib/fluent/plugin_helper/child_process.rb @@ -257,7 +257,8 @@ def child_process_execute_once( readio = writeio = stderrio = wait_thread = nil readio_in_use = writeio_in_use = stderrio_in_use = false - if !mode.include?(:stderr) && !mode.include?(:read_with_stderr) && stderr != :discard # connect + if !mode.include?(:stderr) && !mode.include?(:read_with_stderr) + spawn_opts[:err] = IO::NULL if stderr == :discard writeio, readio, wait_thread = *Open3.popen2(*spawn_args, spawn_opts) elsif mode.include?(:read_with_stderr) writeio, readio, wait_thread = *Open3.popen2e(*spawn_args, spawn_opts) @@ -281,7 +282,7 @@ def child_process_execute_once( stderrio.set_encoding(external_encoding, internal_encoding, encoding_options) stderrio_in_use = true else - stderrio.reopen(IO::NULL) if stderrio && stderrio == :discard + stderrio.reopen(IO::NULL) if stderrio && stderr == :discard end pid = wait_thread.pid # wait_thread => Process::Waiter diff --git a/test/plugin_helper/test_child_process.rb b/test/plugin_helper/test_child_process.rb index 8b71f0726a..799dba59de 100644 --- a/test/plugin_helper/test_child_process.rb +++ b/test/plugin_helper/test_child_process.rb @@ -124,6 +124,43 @@ def configure(conf) assert_equal expected, ary end + test 'can execute external command at just once, which can handle both of read and write. Ignore stderr message/no block' do + m = Mutex.new + ary = [] + Timeout.timeout(TEST_DEADLOCK_TIMEOUT) do + ran = false + # lots of stderr message should not be blocked and message should not be printed in test. + cmd = "ruby -e 'while !STDIN.eof? && line = STDIN.readline; STDERR.puts line.chomp * 1000; STDOUT.puts line.chomp; STDOUT.flush rescue nil; end'" + @d.child_process_execute(:t2_and_ignore_stderr, cmd, mode: [:write, :read]) do |writeio, readio| + m.lock + ran = true + + [[1,2],[3,4],[5,6]].each do |i,j| + writeio.write "my data#{i}\n" + writeio.write "my data#{j}\n" + writeio.flush + end + writeio.close + + while line = readio.readline + ary << line + end + m.unlock + end + begin + sleep TEST_WAIT_INTERVAL_FOR_BLOCK_RUNNING until m.locked? || ran + m.lock + rescue + ensure + m.unlock + end + end + + assert_equal [], @d.log.out.logs + expected = (1..6).map{|i| "my data#{i}\n" } + assert_equal expected, ary + end + test 'can execute external command at just once, which can handle all of read, write and stderr' do m = Mutex.new ary1 = []