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
diff --git a/test/plugin/test_in_exec.rb b/test/plugin/test_in_exec.rb
index f7c9f6d705..59b5461741 100644
--- a/test/plugin/test_in_exec.rb
+++ b/test/plugin/test_in_exec.rb
@@ -295,4 +295,48 @@ 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: 5) do
+ sleep 1 # avoid to return test immediately
+ end
+ elapsed = Time.now - start_time
+ assert (elapsed >= 1.0 and elapsed < 5), "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