-
Notifications
You must be signed in to change notification settings - Fork 420
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
TimerTask uses timeout interval #526
Conversation
@@ -243,7 +243,7 @@ def trigger_observable(observable) | |||
end | |||
|
|||
it 'notifies all observers on timeout' do | |||
subject = TimerTask.new(execution: 0.1, timeout: 0.1) { sleep } | |||
subject = TimerTask.new(execution: 500, timeout: 0.1, run_now: true) { sleep } |
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.
This change makes the test invalid. The idea here is this:
- Create a task that begins its execution
0.1
seconds after creation. - Tell the task to issue a timeout error if the task does not complete after
0.1
seconds.- The timeout error should be issued
0.2
seconds aftersubject.execute
is called.
- The timeout error should be issued
- Add an observer to track the results.
- Execute the task, beginning the
0.1
second timer before the block is run. - Wait
1.0
seconds then check for a timeout.
Since the total time of the task should be approximately 0.2
seconds, we should see the timeout error before the countdown latch expires. If we change the execution_interval
to 500
seconds then the block will not execute before the latch expires. We should not see a timeout error. The fact that the test passes indicates an error, but I believe the error is with the handling of timeout_interval
and not execution_interval
.
I'll look at this in more detail over the weekend.
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.
Thanks for that extremely detailed description. That makes sense.
Here's a failing test that better exposes the bug I'm seeing with timeout_interval
not being used.
it 'should not timeout' do
subject = TimerTask.new(execution: 0.1, timeout: 1) { sleep(0.5); 42 }
subject.add_observer(observer)
subject.execute
observer.latch.wait(2)
expect(observer.ex).to be_nil
expect(observer.value).to eq(42)
subject.kill
end
# Failures:
#
# 1) Concurrent::TimerTask observation should not timeout
# Failure/Error: expect(observer.ex).to be_nil
# expected: nil
# got: #<Concurrent::TimeoutError: Concurrent::TimeoutError>
# # ./spec/concurrent/timer_task_spec.rb:250:in `block (3 levels) in <module:Concurrent>'
Execute a task every 0.1s that takes 0.5s to complete with a 1s timeout. This task will be timed out after 0.1s because execution_interval
is used to trigger the timeout.
My modification of the existing timeout test was to expose the other side of this same bug. Create a long-running task that runs immediatley with a short timeout_interval
and long enough execution_interval
to make it clear it won't be run more than once during the test. I expect the task to time out after timeout_interval
is exceeded but the result is the test will fail after waiting for the task to complete.
d737093
to
daeb8ab
Compare
We have exactly the same problem. If you look over the project you'll see that the value for In our particular case it is causing thread leaking because the And because the timeout is happening at the |
For example, we have the following code in https://github.com/phstc/shoryuken causing a thread-leaking issue: ruby-shoryuken/shoryuken#338 HEARTBEAT_INTERVAL = 0.1
@heartbeat = Concurrent::TimerTask.new(run_now: true,
execution_interval: HEARTBEAT_INTERVAL,
timeout_interval: 60) { dispatch } Sometimes Because the By the time the job gets around to being executed again, there are 200 extra requests waiting to be run and this just repeats ad-infinitum until the process runs out of threads. |
I am closing this PR and I'll fix #525 in a different PR. |
@waynerobinson Thanks for letting us know about the leaking threads, that's serious I have a look. |
Fixes #525. I modified the existing timeout spec to execute immediately and asserts that a timeout occurs but I could just as easily create a new spec to test this behavior.