From ff8c3064731dc4ebf3cb19e5a3fbd34e3d7ecb67 Mon Sep 17 00:00:00 2001 From: zoklk Date: Fri, 10 Apr 2026 17:01:49 +0900 Subject: [PATCH 1/3] feat(in_exec): add command_timeout option to limit child process execution time Signed-off-by: zoklk --- lib/fluent/plugin/in_exec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/fluent/plugin/in_exec.rb b/lib/fluent/plugin/in_exec.rb index 7f932ee1f2..de4aa4647c 100644 --- a/lib/fluent/plugin/in_exec.rb +++ b/lib/fluent/plugin/in_exec.rb @@ -43,6 +43,8 @@ class ExecInput < Fluent::Plugin::Input config_param :tag, :string, default: nil desc 'The interval time between periodic program runs.' config_param :run_interval, :time, default: nil + desc 'Command (program) execution timeout.' + config_param :command_timeout, :time, default: nil desc 'The default block size to read if parser requires partial read.' config_param :read_block_size, :size, default: 10240 # 10k desc 'The encoding to receive the result of the command, especially for non-ascii characters.' @@ -86,9 +88,9 @@ def start options[:external_encoding] = @encoding if @encoding if @run_interval - child_process_execute(:exec_input, @command, interval: @run_interval, **options, &method(:run)) + child_process_execute(:exec_input, @command, interval: @run_interval, wait_timeout: @command_timeout, **options, &method(:run)) else - child_process_execute(:exec_input, @command, immediate: true, **options, &method(:run)) + child_process_execute(:exec_input, @command, immediate: true, wait_timeout: @command_timeout, **options, &method(:run)) end end From 0ccbe6970eb97dd5cfa8e6bf00815c0fb64d07bd Mon Sep 17 00:00:00 2001 From: zoklk Date: Fri, 10 Apr 2026 08:17:08 +0000 Subject: [PATCH 2/3] test(in_exec): add test cases for command_timeout option Signed-off-by: zoklk --- test/plugin/test_in_exec.rb | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/plugin/test_in_exec.rb b/test/plugin/test_in_exec.rb index f7c9f6d705..4a882059f0 100644 --- a/test/plugin/test_in_exec.rb +++ b/test/plugin/test_in_exec.rb @@ -295,4 +295,47 @@ def create_driver(conf) assert_match(/LoadError/, event[2]['message']) end end + sub_test_case 'command_timeout' do + test 'configure command_timeout' do + d = create_driver %[ + command ruby -e "sleep 10" + tag test + run_interval 1s + command_timeout 1s + + @type none + + ] + assert_equal 1.0, d.instance.command_timeout + end + + test 'command_timeout kills long-running child process' do + d = create_driver %[ + command ruby -e "sleep 10" + tag test + run_interval 5s + command_timeout 1s + + @type none + + ] + start_time = Time.now + d.run(timeout: 3) + elapsed = Time.now - start_time + + assert elapsed < 4, "command should have been killed by command_timeout" + end + + test 'command_timeout defaults to nil' do + d = create_driver %[ + command ruby -e "puts 'hello'" + tag test + run_interval 1s + + @type none + + ] + assert_nil d.instance.command_timeout + end + end end From 136f8f98057c0be1ef5f649f6395b51a38f58b39 Mon Sep 17 00:00:00 2001 From: zoklk Date: Mon, 13 Apr 2026 12:01:01 +0000 Subject: [PATCH 3/3] test(in_exec): fix command_timeout test to prevent immediate return Signed-off-by: zoklk --- test/plugin/test_in_exec.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/plugin/test_in_exec.rb b/test/plugin/test_in_exec.rb index 4a882059f0..59b5461741 100644 --- a/test/plugin/test_in_exec.rb +++ b/test/plugin/test_in_exec.rb @@ -320,10 +320,11 @@ def create_driver(conf) ] start_time = Time.now - d.run(timeout: 3) + d.run(timeout: 5) do + sleep 1 # avoid to return test immediately + end elapsed = Time.now - start_time - - assert elapsed < 4, "command should have been killed by command_timeout" + assert (elapsed >= 1.0 and elapsed < 5), "command should have been killed by command_timeout" end test 'command_timeout defaults to nil' do