appsignal 4.0.2-java → 4.0.4-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/lib/appsignal/check_in/cron.rb +2 -34
- data/lib/appsignal/check_in/scheduler.rb +192 -0
- data/lib/appsignal/check_in.rb +18 -0
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +3 -12
- data/lib/appsignal/hooks/at_exit.rb +2 -1
- data/lib/appsignal/integrations/railtie.rb +2 -7
- data/lib/appsignal/rack/body_wrapper.rb +15 -0
- data/lib/appsignal/transmitter.rb +30 -7
- data/lib/appsignal/utils/ndjson.rb +15 -0
- data/lib/appsignal/utils.rb +1 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -0
- data/spec/lib/appsignal/check_in/cron_spec.rb +210 -0
- data/spec/lib/appsignal/check_in/scheduler_spec.rb +484 -0
- data/spec/lib/appsignal/config_spec.rb +0 -25
- data/spec/lib/appsignal/environment_spec.rb +23 -2
- data/spec/lib/appsignal/hooks/at_exit_spec.rb +11 -0
- data/spec/lib/appsignal/integrations/railtie_spec.rb +27 -6
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +29 -21
- data/spec/lib/appsignal/transmitter_spec.rb +48 -2
- data/spec/lib/appsignal_spec.rb +5 -0
- data/spec/support/helpers/take_at_most_helper.rb +21 -0
- metadata +7 -3
- data/spec/lib/appsignal/check_in_spec.rb +0 -136
@@ -0,0 +1,210 @@
|
|
1
|
+
describe Appsignal::CheckIn::Cron do
|
2
|
+
let(:config) { project_fixture_config }
|
3
|
+
let(:cron_checkin) { described_class.new(:identifier => "cron-checkin-name") }
|
4
|
+
let(:transmitter) { Appsignal::Transmitter.new("https://checkin-endpoint.invalid") }
|
5
|
+
let(:scheduler) { Appsignal::CheckIn::Scheduler.new }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(Appsignal).to receive(:active?).and_return(true)
|
9
|
+
config.logger = Logger.new(StringIO.new)
|
10
|
+
allow(Appsignal::CheckIn).to receive(:scheduler).and_return(scheduler)
|
11
|
+
allow(Appsignal::CheckIn).to receive(:transmitter).and_return(transmitter)
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
scheduler.stop
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "when Appsignal is not active" do
|
19
|
+
it "should not transmit any events" do
|
20
|
+
allow(Appsignal).to receive(:active?).and_return(false)
|
21
|
+
|
22
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
23
|
+
message.include?("Cannot transmit cron check-in `cron-checkin-name` start event") &&
|
24
|
+
message.include?("AppSignal is not active")
|
25
|
+
end)
|
26
|
+
|
27
|
+
cron_checkin.start
|
28
|
+
|
29
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
30
|
+
message.include?("Cannot transmit cron check-in `cron-checkin-name` finish event") &&
|
31
|
+
message.include?("AppSignal is not active")
|
32
|
+
end)
|
33
|
+
|
34
|
+
cron_checkin.finish
|
35
|
+
|
36
|
+
expect(transmitter).not_to receive(:transmit)
|
37
|
+
|
38
|
+
scheduler.stop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "when AppSignal is stopped" do
|
43
|
+
it "should not transmit any events" do
|
44
|
+
expect(transmitter).not_to receive(:transmit)
|
45
|
+
|
46
|
+
expect(Appsignal.internal_logger).to receive(:debug).with("Stopping AppSignal")
|
47
|
+
|
48
|
+
Appsignal.stop
|
49
|
+
|
50
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
51
|
+
message.include?("Cannot transmit cron check-in `cron-checkin-name` start event") &&
|
52
|
+
message.include?("AppSignal is stopped")
|
53
|
+
end)
|
54
|
+
|
55
|
+
cron_checkin.start
|
56
|
+
|
57
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
58
|
+
message.include?("Cannot transmit cron check-in `cron-checkin-name` finish event") &&
|
59
|
+
message.include?("AppSignal is stopped")
|
60
|
+
end)
|
61
|
+
|
62
|
+
cron_checkin.finish
|
63
|
+
|
64
|
+
expect(Appsignal.internal_logger).to receive(:debug).with("Stopping AppSignal")
|
65
|
+
|
66
|
+
Appsignal.stop
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#start" do
|
71
|
+
it "should send a cron check-in start" do
|
72
|
+
expect(Appsignal.internal_logger).not_to receive(:error)
|
73
|
+
|
74
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
75
|
+
message.include?("Scheduling cron check-in `cron-checkin-name` start event")
|
76
|
+
end)
|
77
|
+
|
78
|
+
cron_checkin.start
|
79
|
+
|
80
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
81
|
+
message.include?("Transmitted cron check-in `cron-checkin-name` start event")
|
82
|
+
end)
|
83
|
+
|
84
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
85
|
+
:identifier => "cron-checkin-name",
|
86
|
+
:kind => "start",
|
87
|
+
:check_in_type => "cron"
|
88
|
+
)], :format => :ndjson).and_return(Net::HTTPResponse.new(nil, "200", nil))
|
89
|
+
|
90
|
+
scheduler.stop
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should log an error if it fails" do
|
94
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
95
|
+
message.include?("Scheduling cron check-in `cron-checkin-name` start event")
|
96
|
+
end)
|
97
|
+
|
98
|
+
cron_checkin.start
|
99
|
+
|
100
|
+
expect(Appsignal.internal_logger).to receive(:error).with(satisfy do |message|
|
101
|
+
message.include?("Failed to transmit cron check-in `cron-checkin-name` start event") &&
|
102
|
+
message.include?("499 status code")
|
103
|
+
end)
|
104
|
+
|
105
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
106
|
+
:identifier => "cron-checkin-name",
|
107
|
+
:kind => "start",
|
108
|
+
:check_in_type => "cron"
|
109
|
+
)], :format => :ndjson).and_return(Net::HTTPResponse.new(nil, "499", nil))
|
110
|
+
|
111
|
+
scheduler.stop
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#finish" do
|
116
|
+
it "should send a cron check-in finish" do
|
117
|
+
expect(Appsignal.internal_logger).not_to receive(:error)
|
118
|
+
|
119
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
120
|
+
message.include?("Scheduling cron check-in `cron-checkin-name` finish event")
|
121
|
+
end)
|
122
|
+
|
123
|
+
cron_checkin.finish
|
124
|
+
|
125
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
126
|
+
message.include?("Transmitted cron check-in `cron-checkin-name` finish event")
|
127
|
+
end)
|
128
|
+
|
129
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
130
|
+
:identifier => "cron-checkin-name",
|
131
|
+
:kind => "finish",
|
132
|
+
:check_in_type => "cron"
|
133
|
+
)], :format => :ndjson).and_return(Net::HTTPResponse.new(nil, "200", nil))
|
134
|
+
|
135
|
+
scheduler.stop
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should log an error if it fails" do
|
139
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
140
|
+
message.include?("Scheduling cron check-in `cron-checkin-name` finish event")
|
141
|
+
end)
|
142
|
+
|
143
|
+
cron_checkin.finish
|
144
|
+
|
145
|
+
expect(Appsignal.internal_logger).to receive(:error).with(satisfy do |message|
|
146
|
+
message.include?("Failed to transmit cron check-in `cron-checkin-name` finish event") &&
|
147
|
+
message.include?("499 status code")
|
148
|
+
end)
|
149
|
+
|
150
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
151
|
+
:identifier => "cron-checkin-name",
|
152
|
+
:kind => "finish",
|
153
|
+
:check_in_type => "cron"
|
154
|
+
)], :format => :ndjson).and_return(Net::HTTPResponse.new(nil, "499", nil))
|
155
|
+
|
156
|
+
scheduler.stop
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe ".cron" do
|
161
|
+
describe "when a block is given" do
|
162
|
+
it "should send a cron check-in start and finish and return the block output" do
|
163
|
+
expect(scheduler).to receive(:schedule).with(hash_including(
|
164
|
+
:kind => "start",
|
165
|
+
:identifier => "cron-checkin-with-block",
|
166
|
+
:check_in_type => "cron"
|
167
|
+
))
|
168
|
+
|
169
|
+
expect(scheduler).to receive(:schedule).with(hash_including(
|
170
|
+
:kind => "finish",
|
171
|
+
:identifier => "cron-checkin-with-block",
|
172
|
+
:check_in_type => "cron"
|
173
|
+
))
|
174
|
+
|
175
|
+
output = Appsignal::CheckIn.cron("cron-checkin-with-block") { "output" }
|
176
|
+
expect(output).to eq("output")
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should not send a cron check-in finish event when an error is raised" do
|
180
|
+
expect(scheduler).to receive(:schedule).with(hash_including(
|
181
|
+
:kind => "start",
|
182
|
+
:identifier => "cron-checkin-with-block",
|
183
|
+
:check_in_type => "cron"
|
184
|
+
))
|
185
|
+
|
186
|
+
expect(scheduler).not_to receive(:schedule).with(hash_including(
|
187
|
+
:kind => "finish",
|
188
|
+
:identifier => "cron-checkin-with-block",
|
189
|
+
:check_in_type => "cron"
|
190
|
+
))
|
191
|
+
|
192
|
+
expect do
|
193
|
+
Appsignal::CheckIn.cron("cron-checkin-with-block") { raise "error" }
|
194
|
+
end.to raise_error(RuntimeError, "error")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "when no block is given" do
|
199
|
+
it "should only send a cron check-in finish event" do
|
200
|
+
expect(scheduler).to receive(:schedule).with(hash_including(
|
201
|
+
:kind => "finish",
|
202
|
+
:identifier => "cron-checkin-without-block",
|
203
|
+
:check_in_type => "cron"
|
204
|
+
))
|
205
|
+
|
206
|
+
Appsignal::CheckIn.cron("cron-checkin-without-block")
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,484 @@
|
|
1
|
+
describe Appsignal::CheckIn::Scheduler do
|
2
|
+
include WaitForHelper
|
3
|
+
include TakeAtMostHelper
|
4
|
+
|
5
|
+
let(:transmitter) { Appsignal::Transmitter.new("http://checkin-endpoint.invalid") }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(Appsignal).to receive(:active?).and_return(true)
|
9
|
+
allow(transmitter).to receive(:transmit).and_return(Net::HTTPSuccess.new("1.1", 200, "OK"))
|
10
|
+
allow(Appsignal::CheckIn).to receive(:transmitter).and_return(transmitter)
|
11
|
+
allow(Appsignal::CheckIn).to receive(:scheduler).and_return(subject)
|
12
|
+
# Shorten debounce intervals to make the tests run faster.
|
13
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 0.1)
|
14
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 0.1)
|
15
|
+
end
|
16
|
+
|
17
|
+
after do
|
18
|
+
subject.stop
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "when no event is sent" do
|
22
|
+
it "does not start a thread" do
|
23
|
+
expect(subject.thread).to be_nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it "does not schedule a debounce" do
|
27
|
+
expect(subject.waker).to be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can be stopped" do
|
31
|
+
# Set all debounce intervals to 10 seconds, to make the assertion
|
32
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
33
|
+
# tested is that no debounces are awaited when stopping the scheduler.
|
34
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
35
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
36
|
+
|
37
|
+
take_at_most(0.1) do
|
38
|
+
expect { subject.stop }.not_to raise_error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can be stopped more than once" do
|
43
|
+
# Set all debounce intervals to 10 seconds, to make the assertion
|
44
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
45
|
+
# tested is that no debounces are awaited when stopping the scheduler.
|
46
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
47
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
48
|
+
|
49
|
+
take_at_most(0.1) do
|
50
|
+
expect { subject.stop }.not_to raise_error
|
51
|
+
expect { subject.stop }.not_to raise_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "closes the queue when stopped" do
|
56
|
+
subject.stop
|
57
|
+
expect(subject.queue.closed?).to be(true)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "when an event is sent" do
|
62
|
+
it "starts a thread" do
|
63
|
+
Appsignal::CheckIn.cron("test")
|
64
|
+
expect(subject.thread).to be_a(Thread)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "schedules a debounce" do
|
68
|
+
Appsignal::CheckIn.cron("test")
|
69
|
+
expect(subject.waker).to be_a(Thread)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "schedules the event to be transmitted" do
|
73
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
74
|
+
:identifier => "test",
|
75
|
+
:check_in_type => "cron",
|
76
|
+
:kind => "finish"
|
77
|
+
)], :format => :ndjson)
|
78
|
+
|
79
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
80
|
+
message.include?("Scheduling cron check-in `test` finish event")
|
81
|
+
end)
|
82
|
+
|
83
|
+
expect(subject.events).to be_empty
|
84
|
+
|
85
|
+
Appsignal::CheckIn.cron("test")
|
86
|
+
|
87
|
+
expect(subject.events).not_to be_empty
|
88
|
+
|
89
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
90
|
+
message.include?("Transmitted cron check-in `test` finish event")
|
91
|
+
end)
|
92
|
+
|
93
|
+
wait_for("the event to be transmitted") { subject.transmitted == 1 }
|
94
|
+
|
95
|
+
expect(subject.events).to be_empty
|
96
|
+
end
|
97
|
+
|
98
|
+
it "waits for the event to be transmitted when stopped" do
|
99
|
+
# Set all debounce intervals to 10 seconds, to make the test
|
100
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
101
|
+
# tested is that the events are transmitted immediately when the
|
102
|
+
# scheduler is stopped, without waiting for any debounce.
|
103
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
104
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
105
|
+
|
106
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
107
|
+
:identifier => "test",
|
108
|
+
:check_in_type => "cron",
|
109
|
+
:kind => "finish"
|
110
|
+
)], :format => :ndjson)
|
111
|
+
|
112
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
113
|
+
message.include?("Scheduling cron check-in `test` finish event")
|
114
|
+
end)
|
115
|
+
|
116
|
+
Appsignal::CheckIn.cron("test")
|
117
|
+
|
118
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
119
|
+
message.include?("Transmitted cron check-in `test` finish event")
|
120
|
+
end)
|
121
|
+
|
122
|
+
expect(subject.events).not_to be_empty
|
123
|
+
|
124
|
+
take_at_most(0.1) do
|
125
|
+
expect { subject.stop }.not_to raise_error
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check that the thread wasn't killed before the transmission was
|
129
|
+
# completed.
|
130
|
+
expect(subject.transmitted).to eq(1)
|
131
|
+
|
132
|
+
expect(subject.events).to be_empty
|
133
|
+
end
|
134
|
+
|
135
|
+
it "can be stopped more than once" do
|
136
|
+
# Set all debounce intervals to 10 seconds, to make the test
|
137
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
138
|
+
# tested is that the events are transmitted immediately when the
|
139
|
+
# scheduler is stopped, without waiting for the debounce interval.
|
140
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
141
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
142
|
+
|
143
|
+
Appsignal::CheckIn.cron("test")
|
144
|
+
take_at_most(0.1) do
|
145
|
+
expect { subject.stop }.not_to raise_error
|
146
|
+
end
|
147
|
+
|
148
|
+
# Check that the thread wasn't killed before the transmission was
|
149
|
+
# completed.
|
150
|
+
expect(subject.transmitted).to eq(1)
|
151
|
+
|
152
|
+
take_at_most(0.1) do
|
153
|
+
expect { subject.stop }.not_to raise_error
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it "closes the queue when stopped" do
|
158
|
+
Appsignal::CheckIn.cron("test")
|
159
|
+
subject.stop
|
160
|
+
expect(subject.queue.closed?).to be(true)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "kills the thread when stopped" do
|
164
|
+
Appsignal::CheckIn.cron("test")
|
165
|
+
subject.stop
|
166
|
+
expect(subject.thread.alive?).to be(false)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "unschedules the debounce when stopped" do
|
170
|
+
Appsignal::CheckIn.cron("test")
|
171
|
+
waker = subject.waker
|
172
|
+
subject.stop
|
173
|
+
expect(waker.alive?).to be(false)
|
174
|
+
expect(subject.waker).to be_nil
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "when many events are sent" do
|
179
|
+
describe "within the short debounce interval" do
|
180
|
+
it "transmits all events at once" do
|
181
|
+
expect(transmitter).to receive(:transmit).with(
|
182
|
+
["first", "second", "third"].map do |identifier|
|
183
|
+
hash_including(
|
184
|
+
:identifier => identifier,
|
185
|
+
:check_in_type => "cron",
|
186
|
+
:kind => "finish"
|
187
|
+
)
|
188
|
+
end, :format => :ndjson
|
189
|
+
)
|
190
|
+
|
191
|
+
Appsignal::CheckIn.cron("first")
|
192
|
+
Appsignal::CheckIn.cron("second")
|
193
|
+
Appsignal::CheckIn.cron("third")
|
194
|
+
|
195
|
+
wait_for("the events to be transmitted") { subject.transmitted == 1 }
|
196
|
+
end
|
197
|
+
|
198
|
+
it "transmits all events at once when stopped" do
|
199
|
+
# Set a short debounce interval of 10 seconds, to make the final wait
|
200
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
201
|
+
# tested is that the events are transmitted when the scheduler is
|
202
|
+
# stopped.
|
203
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
204
|
+
|
205
|
+
expect(transmitter).to receive(:transmit).with(
|
206
|
+
["first", "second", "third"].map do |identifier|
|
207
|
+
hash_including(
|
208
|
+
:identifier => identifier,
|
209
|
+
:check_in_type => "cron",
|
210
|
+
:kind => "finish"
|
211
|
+
)
|
212
|
+
end, :format => :ndjson
|
213
|
+
)
|
214
|
+
|
215
|
+
Appsignal::CheckIn.cron("first")
|
216
|
+
Appsignal::CheckIn.cron("second")
|
217
|
+
Appsignal::CheckIn.cron("third")
|
218
|
+
|
219
|
+
subject.stop
|
220
|
+
|
221
|
+
wait_for("the events to be transmitted") { subject.transmitted == 1 }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "further apart than the short debounce interval" do
|
226
|
+
it "transmits the first event and enqueues future events" do
|
227
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
228
|
+
:identifier => "first",
|
229
|
+
:check_in_type => "cron",
|
230
|
+
:kind => "finish"
|
231
|
+
)], :format => :ndjson)
|
232
|
+
|
233
|
+
Appsignal::CheckIn.cron("first")
|
234
|
+
|
235
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
236
|
+
|
237
|
+
Appsignal::CheckIn.cron("second")
|
238
|
+
Appsignal::CheckIn.cron("third")
|
239
|
+
|
240
|
+
expect(subject.events).to match(["second", "third"].map do |identifier|
|
241
|
+
hash_including({
|
242
|
+
:identifier => identifier,
|
243
|
+
:check_in_type => "cron",
|
244
|
+
:kind => "finish"
|
245
|
+
})
|
246
|
+
end)
|
247
|
+
end
|
248
|
+
|
249
|
+
it "transmits the other events after the debounce interval" do
|
250
|
+
expect(transmitter).to receive(:transmit)
|
251
|
+
|
252
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
253
|
+
message.include?("Scheduling cron check-in `first` finish event")
|
254
|
+
end)
|
255
|
+
|
256
|
+
Appsignal::CheckIn.cron("first")
|
257
|
+
|
258
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
259
|
+
message.include?("Transmitted cron check-in `first` finish event")
|
260
|
+
end)
|
261
|
+
|
262
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
263
|
+
|
264
|
+
expect(transmitter).to receive(:transmit).with(
|
265
|
+
["second", "third"].map do |identifier|
|
266
|
+
hash_including(
|
267
|
+
:identifier => identifier,
|
268
|
+
:check_in_type => "cron",
|
269
|
+
:kind => "finish"
|
270
|
+
)
|
271
|
+
end, :format => :ndjson
|
272
|
+
)
|
273
|
+
|
274
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
275
|
+
message.include?("Scheduling cron check-in `second` finish event")
|
276
|
+
end)
|
277
|
+
|
278
|
+
Appsignal::CheckIn.cron("second")
|
279
|
+
|
280
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
281
|
+
message.include?("Scheduling cron check-in `third` finish event")
|
282
|
+
end)
|
283
|
+
|
284
|
+
Appsignal::CheckIn.cron("third")
|
285
|
+
|
286
|
+
expect(subject.events).to_not be_empty
|
287
|
+
|
288
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(
|
289
|
+
"Transmitted 2 check-in events"
|
290
|
+
)
|
291
|
+
|
292
|
+
wait_for("the other events to be transmitted") { subject.transmitted == 2 }
|
293
|
+
|
294
|
+
expect(subject.events).to be_empty
|
295
|
+
end
|
296
|
+
|
297
|
+
it "transmits the other events when stopped" do
|
298
|
+
# Restore the original long debounce interval of 10 seconds, to make
|
299
|
+
# the final wait fail if it waits for the debounce -- this ensures
|
300
|
+
# that what is being tested is that the events are transmitted
|
301
|
+
# immediately when the scheduler is stopped.
|
302
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
303
|
+
|
304
|
+
expect(transmitter).to receive(:transmit)
|
305
|
+
|
306
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
307
|
+
message.include?("Scheduling cron check-in `first` finish event")
|
308
|
+
end)
|
309
|
+
|
310
|
+
Appsignal::CheckIn.cron("first")
|
311
|
+
|
312
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
313
|
+
message.include?("Transmitted cron check-in `first` finish event")
|
314
|
+
end)
|
315
|
+
|
316
|
+
wait_for("the event to be transmitted") { subject.transmitted == 1 }
|
317
|
+
|
318
|
+
expect(transmitter).to receive(:transmit).with(
|
319
|
+
["second", "third"].map do |identifier|
|
320
|
+
hash_including(
|
321
|
+
:identifier => identifier,
|
322
|
+
:check_in_type => "cron",
|
323
|
+
:kind => "finish"
|
324
|
+
)
|
325
|
+
end, :format => :ndjson
|
326
|
+
)
|
327
|
+
|
328
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
329
|
+
message.include?("Scheduling cron check-in `second` finish event")
|
330
|
+
end)
|
331
|
+
|
332
|
+
Appsignal::CheckIn.cron("second")
|
333
|
+
|
334
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
335
|
+
message.include?("Scheduling cron check-in `third` finish event")
|
336
|
+
end)
|
337
|
+
|
338
|
+
Appsignal::CheckIn.cron("third")
|
339
|
+
|
340
|
+
expect(subject.events).to_not be_empty
|
341
|
+
|
342
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(
|
343
|
+
"Transmitted 2 check-in events"
|
344
|
+
)
|
345
|
+
|
346
|
+
subject.stop
|
347
|
+
|
348
|
+
wait_for("the other events to be transmitted") { subject.transmitted == 2 }
|
349
|
+
|
350
|
+
expect(subject.events).to be_empty
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
describe "when a similar event is sent more than once" do
|
356
|
+
it "only transmits one of the similar events" do
|
357
|
+
# We must instantiate `Appsignal::CheckIn::Cron` directly, as the
|
358
|
+
# `.cron` helper would use a different digest for each invocation.
|
359
|
+
cron = Appsignal::CheckIn::Cron.new(:identifier => "test")
|
360
|
+
|
361
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
362
|
+
:identifier => "test",
|
363
|
+
:check_in_type => "cron",
|
364
|
+
:kind => "start"
|
365
|
+
)], :format => :ndjson)
|
366
|
+
|
367
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(
|
368
|
+
"Scheduling cron check-in `test` start event (digest #{cron.digest}) to be transmitted"
|
369
|
+
)
|
370
|
+
|
371
|
+
cron.start
|
372
|
+
|
373
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(
|
374
|
+
"Scheduling cron check-in `test` start event (digest #{cron.digest}) to be transmitted"
|
375
|
+
)
|
376
|
+
|
377
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(
|
378
|
+
"Replacing previously scheduled cron check-in `test` start event (digest #{cron.digest})"
|
379
|
+
)
|
380
|
+
|
381
|
+
cron.start
|
382
|
+
|
383
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(
|
384
|
+
"Transmitted cron check-in `test` start event (digest #{cron.digest})"
|
385
|
+
)
|
386
|
+
|
387
|
+
wait_for("the event to be transmitted") { subject.transmitted == 1 }
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "when the scheduler is stopped" do
|
392
|
+
it "does not schedule any events to be transmitted" do
|
393
|
+
expect(transmitter).not_to receive(:transmit)
|
394
|
+
|
395
|
+
subject.stop
|
396
|
+
|
397
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
398
|
+
message.include?("Cannot transmit cron check-in `test` finish event") &&
|
399
|
+
message.include?("AppSignal is stopped")
|
400
|
+
end)
|
401
|
+
|
402
|
+
Appsignal::CheckIn.cron("test")
|
403
|
+
|
404
|
+
expect(subject.events).to be_empty
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
describe "when AppSignal is not active" do
|
409
|
+
it "does not schedule any events to be transmitted" do
|
410
|
+
allow(Appsignal).to receive(:active?).and_return(false)
|
411
|
+
|
412
|
+
subject.stop
|
413
|
+
|
414
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
415
|
+
message.include?("Cannot transmit cron check-in `test` finish event") &&
|
416
|
+
message.include?("AppSignal is not active")
|
417
|
+
end)
|
418
|
+
|
419
|
+
Appsignal::CheckIn.cron("test")
|
420
|
+
|
421
|
+
expect(subject.events).to be_empty
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
describe "when transmitting returns a non-success response code" do
|
426
|
+
it "logs the error and continues" do
|
427
|
+
expect(transmitter).to receive(:transmit).and_return(
|
428
|
+
Net::HTTPNotFound.new("1.1", 404, "Not Found")
|
429
|
+
)
|
430
|
+
|
431
|
+
Appsignal::CheckIn.cron("first")
|
432
|
+
|
433
|
+
expect(Appsignal.internal_logger).to receive(:error).with(satisfy do |message|
|
434
|
+
message.include?("Failed to transmit cron check-in `first` finish event") &&
|
435
|
+
message.include?("404 status code")
|
436
|
+
end)
|
437
|
+
|
438
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
439
|
+
|
440
|
+
expect(transmitter).to receive(:transmit).and_return(
|
441
|
+
Net::HTTPSuccess.new("1.1", 200, "OK")
|
442
|
+
)
|
443
|
+
|
444
|
+
Appsignal::CheckIn.cron("second")
|
445
|
+
|
446
|
+
expect(Appsignal.internal_logger).not_to receive(:error)
|
447
|
+
|
448
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
449
|
+
message.include?("Transmitted cron check-in `second` finish event")
|
450
|
+
end)
|
451
|
+
|
452
|
+
wait_for("the second event to be transmitted") { subject.transmitted == 2 }
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
describe "when transmitting throws an error" do
|
457
|
+
it "logs the error and continues" do
|
458
|
+
expect(transmitter).to receive(:transmit).and_raise("Something went wrong")
|
459
|
+
|
460
|
+
Appsignal::CheckIn.cron("first")
|
461
|
+
|
462
|
+
expect(Appsignal.internal_logger).to receive(:error).with(satisfy do |message|
|
463
|
+
message.include?("Failed to transmit cron check-in `first` finish event") &&
|
464
|
+
message.include?("Something went wrong")
|
465
|
+
end)
|
466
|
+
|
467
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
468
|
+
|
469
|
+
expect(transmitter).to receive(:transmit).and_return(
|
470
|
+
Net::HTTPSuccess.new("1.1", 200, "OK")
|
471
|
+
)
|
472
|
+
|
473
|
+
Appsignal::CheckIn.cron("second")
|
474
|
+
|
475
|
+
expect(Appsignal.internal_logger).not_to receive(:error)
|
476
|
+
|
477
|
+
expect(Appsignal.internal_logger).to receive(:debug).with(satisfy do |message|
|
478
|
+
message.include?("Transmitted cron check-in `second` finish event")
|
479
|
+
end)
|
480
|
+
|
481
|
+
wait_for("the second event to be transmitted") { subject.transmitted == 2 }
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|