mirror of
https://github.com/l5yth/potato-mesh.git
synced 2026-10-30 19:41:58 +01:00
web,data: timeout specs hold their jobs on gates, not fixed sleeps (#1050)
This commit is contained in:
3 files changed
+42
-18
No files matched your search
@@ -126,10 +126,16 @@ def test_close_interface_respects_timeout(monkeypatch):
|
|||||||
|
|
||||||
class SlowInterface:
|
class SlowInterface:
|
||||||
def close(self):
|
def close(self):
|
||||||
blocker.wait(timeout=0.1)
|
# Held until the test releases it, so the close still runs however
|
||||||
|
# late the 0.01 s join returns. After 5 s it ends anyway, so a
|
||||||
|
# _close_interface that waits for the close fails instead of hanging.
|
||||||
|
blocker.wait(timeout=5.0)
|
||||||
|
|
||||||
daemon._close_interface(SlowInterface())
|
try:
|
||||||
assert any("timeout_seconds" in entry for entry in log_calls)
|
daemon._close_interface(SlowInterface())
|
||||||
|
assert any("timeout_seconds" in entry for entry in log_calls)
|
||||||
|
finally:
|
||||||
|
blocker.set()
|
||||||
|
|
||||||
|
|
||||||
def test_close_interface_immediate_path(monkeypatch):
|
def test_close_interface_immediate_path(monkeypatch):
|
||||||
|
|||||||
@@ -403,26 +403,30 @@ RSpec.describe "Federation crawl limits" do
|
|||||||
|
|
||||||
it "lets the worker pool's task timeout end a crawl" do
|
it "lets the worker pool's task timeout end a crawl" do
|
||||||
fed.lists[hostile] = %w[p1 p2 p3 p4].map { |name| peers.record("#{name}.fed.invalid") }
|
fed.lists[hostile] = %w[p1 p2 p3 p4].map { |name| peers.record("#{name}.fed.invalid") }
|
||||||
|
# The first request holds until the pool's task timeout interrupts it,
|
||||||
|
# however late that fires, so the crawl cannot go on by itself. After 5 s
|
||||||
|
# it ends anyway, so a pool and a wait that both ignore their timeouts
|
||||||
|
# fail, not hang.
|
||||||
|
gate = Queue.new
|
||||||
first = true
|
first = true
|
||||||
fed.hooks << lambda do |_entry|
|
fed.hooks << lambda do |_entry|
|
||||||
if first
|
if first
|
||||||
first = false
|
first = false
|
||||||
sleep 0.6
|
gate.pop(timeout: 5)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
worker_pool = PotatoMesh::App::WorkerPool.new(size: 1, max_queue: 2, task_timeout: 0.3, name: "spec-fl6")
|
worker_pool = PotatoMesh::App::WorkerPool.new(size: 1, max_queue: 2, task_timeout: 0.3, name: "spec-fl6")
|
||||||
|
|
||||||
task = worker_pool.schedule { crawl(hostile) }
|
task = worker_pool.schedule { crawl(hostile) }
|
||||||
outcome = begin
|
begin
|
||||||
task.wait(timeout: 5)
|
# The pool's message: the wait's own deadline raises "task deadline
|
||||||
:completed
|
# exceeded", which is no task timeout ending the crawl (SPEC FL6).
|
||||||
rescue PotatoMesh::App::WorkerPool::TaskTimeoutError
|
expect { task.wait(timeout: 3) }.to raise_error(PotatoMesh::App::WorkerPool::TaskTimeoutError, "task exceeded timeout")
|
||||||
:timed_out
|
ensure
|
||||||
ensure
|
gate.close
|
||||||
worker_pool.shutdown(timeout: 1, force_kill_after: 1)
|
worker_pool.shutdown(timeout: 1, force_kill_after: 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(outcome).to eq(:timed_out)
|
|
||||||
expect(fed.total).to eq(1)
|
expect(fed.total).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,17 @@ RSpec.describe PotatoMesh::App::WorkerPool do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "fails tasks that exceed the configured timeout" do
|
it "fails tasks that exceed the configured timeout" do
|
||||||
|
gate = Queue.new
|
||||||
with_pool(task_timeout: 0.01) do |pool|
|
with_pool(task_timeout: 0.01) do |pool|
|
||||||
task = pool.schedule { sleep 0.05; :late }
|
# The job holds until the pool's task timeout interrupts it, however
|
||||||
expect { task.wait(timeout: 1) }.to raise_error(described_class::TaskTimeoutError)
|
# late that fires. The message is the pool's: the wait's own deadline
|
||||||
|
# raises "task deadline exceeded". After 5 s the job ends anyway, so a
|
||||||
|
# pool and a wait that both ignore their timeouts fail, not hang.
|
||||||
|
task = pool.schedule { gate.pop(timeout: 5); :late }
|
||||||
|
expect { task.wait(timeout: 3) }.to raise_error(described_class::TaskTimeoutError, "task exceeded timeout")
|
||||||
end
|
end
|
||||||
|
ensure
|
||||||
|
gate.close
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ignores invalid timeout values" do
|
it "ignores invalid timeout values" do
|
||||||
@@ -130,13 +137,20 @@ RSpec.describe PotatoMesh::App::WorkerPool do
|
|||||||
|
|
||||||
describe PotatoMesh::App::WorkerPool::Task do
|
describe PotatoMesh::App::WorkerPool::Task do
|
||||||
it "raises a timeout when the job exceeds the provided deadline" do
|
it "raises a timeout when the job exceeds the provided deadline" do
|
||||||
|
gate = Queue.new
|
||||||
with_pool do |pool|
|
with_pool do |pool|
|
||||||
task = pool.schedule { sleep 0.1; :done }
|
# The job holds until the gate opens, so the first wait can only end
|
||||||
|
# at its own deadline, however late it wakes. After 5 s the job ends
|
||||||
|
# anyway, so a wait that ignores its deadline fails instead of hanging.
|
||||||
|
task = pool.schedule { gate.pop(timeout: 5); :done }
|
||||||
expect do
|
expect do
|
||||||
task.wait(timeout: 0.01)
|
task.wait(timeout: 0.01)
|
||||||
end.to raise_error(PotatoMesh::App::WorkerPool::TaskTimeoutError)
|
end.to raise_error(PotatoMesh::App::WorkerPool::TaskTimeoutError, "task deadline exceeded")
|
||||||
expect(task.wait(timeout: 1)).to eq(:done)
|
gate << :open
|
||||||
|
expect(task.wait(timeout: 5)).to eq(:done)
|
||||||
end
|
end
|
||||||
|
ensure
|
||||||
|
gate.close
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reports completion status" do
|
it "reports completion status" do
|
||||||
|
|||||||
Reference in new issue
Block a user