-
Notifications
You must be signed in to change notification settings - Fork 12
data_timeout: decouple blocking duration from data timeout #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,16 +84,15 @@ def handle_socket(socket, output_queue) | |
begin | ||
hostname = Socket.gethostname | ||
while !stop? | ||
data = socket.read_nonblock(16384, exception: false) | ||
|
||
if data == :wait_readable | ||
if @data_timeout == -1 || IO.select([socket], nil, nil, @data_timeout) | ||
next # retry socket read | ||
else | ||
# socket not ready after @data_timeout seconds | ||
@logger.info("Closing connection after read timeout", :path => @path) | ||
return | ||
end | ||
data = io_interruptable_readpartial(socket, 16384, @data_timeout) | ||
|
||
if data == :data_timeout | ||
# socket not ready after @data_timeout seconds | ||
@logger.info("Closing connection after read timeout", :path => @path) | ||
return | ||
elsif data == :stopping | ||
@logger.trace("Shutdown in progress", :path => @path) | ||
next # let next loop handle graceful stop | ||
end | ||
|
||
@codec.decode(data) do |event| | ||
|
@@ -118,6 +117,35 @@ def handle_socket(socket, output_queue) | |
end | ||
end | ||
|
||
## | ||
# Emulates `IO#readpartial` with a timeout and our plugin's stop-condition, | ||
# limiting blocking calls to windows of 10s or less to ensure it can be interrupted. | ||
# | ||
# @param readable_io [IO] the IO to read from | ||
# @param maxlen [Integer] the max bytes to be read | ||
# @param timeout [Number] the maximum number of seconds to , or -1 to disable timeouts | ||
# | ||
# @return [:data_timeout] if timeout was reached before bytes were available | ||
# @return [:stopping] if plugin stop-condition was detected before bytes were available | ||
# @return [String] a non-empty string if bytes became available before the timeout was reached | ||
def io_interruptable_readpartial(readable_io, maxlen, timeout) | ||
|
||
data_timeout_deadline = timeout < 0 ? nil : Time.now + timeout | ||
maximum_blocking_seconds = timeout < 0 || timeout > 10 ? 10 : timeout | ||
|
||
loop do | ||
return :stopping if stop? | ||
result = readable_io.read_nonblock(maxlen, exception: false) | ||
|
||
return result if result.kind_of?(String) | ||
raise EOFError if result.nil? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What would be a case where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. When using |
||
|
||
return :data_timeout if (data_timeout_deadline && data_timeout_deadline < Time.now) | ||
IO.select([readable_io], nil, nil, maximum_blocking_seconds) | ||
end | ||
end | ||
private :io_interruptable_readpartial | ||
|
||
private | ||
def server? | ||
@mode == "server" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we make the log info level for better visibility?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I intentionally added at
trace
level because this is noise about the plugin stopping reads from the socket that is not likely to be useful when a user is going about their normal business and already has signal about the plugin and pipeline getting closed.