mirror of
https://github.com/elastic/logstash.git
synced 2025-04-22 05:37:21 -04:00
139 lines
No EOL
4.1 KiB
Ruby
139 lines
No EOL
4.1 KiB
Ruby
require "logstash/util/retryable"
|
|
|
|
describe LogStash::Retryable do
|
|
class C
|
|
include LogStash::Retryable
|
|
end
|
|
|
|
class E < StandardError; end;
|
|
class F < StandardError; end;
|
|
|
|
subject {C.new}
|
|
|
|
context "with default fixed 1 second retry sleep" do
|
|
|
|
it "should execute once" do
|
|
expect(subject).to receive(:sleep).never
|
|
expect(subject.retryable(:rescue => nil){|i| expect(i).to eq(0); "foo"}).to eq("foo")
|
|
end
|
|
|
|
it "should not retry on non rescued exceptions" do
|
|
i = 0
|
|
expect(subject).to receive(:sleep).never
|
|
expect{subject.retryable(:rescue => E){i += 1; raise F}}.to raise_error(F)
|
|
expect(i).to eq(1)
|
|
end
|
|
|
|
it "should execute once and retry once by default" do
|
|
i = 0
|
|
expect(subject).to receive(:sleep).once.with(1)
|
|
expect{subject.retryable{i += 1; raise E}}.to raise_error(E)
|
|
expect(i).to eq(2)
|
|
end
|
|
|
|
it "should retry on rescued exceptions" do
|
|
i = 0
|
|
expect(subject).to receive(:sleep).once.with(1)
|
|
expect{subject.retryable(:rescue => E){i += 1; raise E}}.to raise_error(E)
|
|
expect(i).to eq(2)
|
|
end
|
|
|
|
it "should retry indefinitely" do
|
|
i = 0
|
|
expect(subject).to receive(:sleep).exactly(50).times.with(1)
|
|
expect{subject.retryable(:tries => 0, :rescue => E){i += 1; raise i <= 50 ? E : F}}.to raise_error(F)
|
|
end
|
|
|
|
it "should execute once and retry once by default and execute on_retry callback" do
|
|
i = 0
|
|
callback_values = []
|
|
|
|
callback = lambda do |retry_count, e|
|
|
callback_values << [retry_count, e]
|
|
end
|
|
|
|
expect(subject).to receive(:sleep).once.with(1)
|
|
|
|
expect do
|
|
subject.retryable(:on_retry => callback){i += 1; raise E}
|
|
end.to raise_error
|
|
|
|
expect(i).to eq(2)
|
|
|
|
expect(callback_values.size).to eq(1)
|
|
expect(callback_values[0][0]).to eq(1)
|
|
expect(callback_values[0][1]).to be_a(E)
|
|
end
|
|
|
|
it "should execute once and retry n times" do
|
|
i = 0
|
|
n = 3
|
|
expect(subject).to receive(:sleep).exactly(n).times.with(1)
|
|
expect{subject.retryable(:tries => n){i += 1; raise E}}.to raise_error(E)
|
|
expect(i).to eq(n + 1)
|
|
end
|
|
|
|
it "should execute once and retry n times and execute on_retry callback" do
|
|
i = 0
|
|
n = 3
|
|
callback_values = []
|
|
|
|
callback = lambda do |retry_count, e|
|
|
callback_values << [retry_count, e]
|
|
end
|
|
|
|
expect(subject).to receive(:sleep).exactly(n).times.with(1)
|
|
|
|
expect do
|
|
subject.retryable(:tries => n, :on_retry => callback){i += 1; raise E}
|
|
end.to raise_error
|
|
|
|
expect(i).to eq(n + 1)
|
|
|
|
expect(callback_values.size).to eq(n)
|
|
n.times.each do |j|
|
|
expect(callback_values[j].first).to eq(j + 1)
|
|
expect(callback_values[j].last).to be_a(E)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with exponential backoff" do
|
|
|
|
it "should execute once and retry once with base sleep by default" do
|
|
expect(subject).to receive(:sleep).once.with(2)
|
|
expect do
|
|
subject.retryable(:base_sleep => 2, :max_sleep => 10){raise E}
|
|
end.to raise_error(E)
|
|
end
|
|
|
|
it "should execute once and retry n times with exponential backoff sleep" do
|
|
n = 3
|
|
s = 0.5
|
|
|
|
n.times.each do |i|
|
|
expect(subject).to receive(:sleep).once.with(s * (2 ** i)).ordered
|
|
end
|
|
expect do
|
|
subject.retryable(:tries => n, :base_sleep => s, :max_sleep => 100){raise E}
|
|
end.to raise_error(E)
|
|
end
|
|
|
|
it "should execute once and retry n times with exponential backoff sleep capping at max_sleep" do
|
|
n = 20
|
|
base_sleep = 0.1
|
|
max_sleep = 1
|
|
|
|
expect(subject).to receive(:sleep).once.with(0.1).ordered
|
|
expect(subject).to receive(:sleep).once.with(0.2).ordered
|
|
expect(subject).to receive(:sleep).once.with(0.4).ordered
|
|
expect(subject).to receive(:sleep).once.with(0.8).ordered
|
|
(n - 4).times.each do |i|
|
|
expect(subject).to receive(:sleep).once.with(1).ordered
|
|
end
|
|
expect do
|
|
subject.retryable(:tries => n, :base_sleep => base_sleep, :max_sleep => max_sleep){raise E}
|
|
end.to raise_error(E)
|
|
end
|
|
end
|
|
end |