airbrake-ruby 4.5.1 → 4.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -245,12 +245,12 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
245
245
 
246
246
  it "appends thread inspect (self)" do
247
247
  subject.call(notice)
248
- expect(notice[:params][:thread][:self]).to match(/\A#<Thread:.+ run>\z/)
248
+ expect(notice[:params][:thread][:self]).to match(/\A#<Thread:.+>\z/)
249
249
  end
250
250
 
251
251
  it "appends thread group" do
252
252
  subject.call(notice)
253
- expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread:.+ run>\z/)
253
+ expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread:.+>\z/)
254
254
  end
255
255
 
256
256
  it "appends priority" do
@@ -12,7 +12,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
12
12
  project_id: 1,
13
13
  project_key: 'banana',
14
14
  performance_stats: true,
15
- performance_stats_flush_period: 0
15
+ performance_stats_flush_period: 0,
16
+ query_stats: true
16
17
  )
17
18
  end
18
19
 
@@ -30,6 +31,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
30
31
  end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
31
32
  )
32
33
  )
34
+ subject.close
33
35
 
34
36
  expect(
35
37
  a_request(:put, queries).with(body: %r|
@@ -59,6 +61,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
59
61
  end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
60
62
  )
61
63
  )
64
+ subject.close
62
65
 
63
66
  expect(
64
67
  a_request(:put, routes).with(body: %r|
@@ -86,6 +89,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
86
89
  groups: { db: 131, view: 421 }
87
90
  )
88
91
  )
92
+ subject.close
89
93
 
90
94
  expect(
91
95
  a_request(:put, breakdowns).with(body: %r|
@@ -125,6 +129,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
125
129
  start_time: Time.new(2018, 1, 1, 0, 0, 20, 0)
126
130
  )
127
131
  )
132
+ subject.close
133
+
128
134
  expect(
129
135
  a_request(:put, routes).with(body: /"time":"2018-01-01T00:00:00\+00:00"/)
130
136
  ).to have_been_made
@@ -147,6 +153,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
147
153
  start_time: Time.new(2018, 1, 1, 0, 0, 50, 0)
148
154
  )
149
155
  )
156
+ subject.close
157
+
150
158
  expect(
151
159
  a_request(:put, routes).with(body: /"count":2/)
152
160
  ).to have_been_made
@@ -171,6 +179,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
171
179
  end_time: Time.new(2018, 1, 1, 0, 1, 55, 0)
172
180
  )
173
181
  )
182
+ subject.close
183
+
174
184
  expect(
175
185
  a_request(:put, routes).with(
176
186
  body: %r|\A
@@ -205,6 +215,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
205
215
  end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
206
216
  )
207
217
  )
218
+ subject.close
219
+
208
220
  expect(
209
221
  a_request(:put, routes).with(
210
222
  body: %r|\A
@@ -241,6 +253,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
241
253
  groups: { db: 55, view: 11 }
242
254
  )
243
255
  )
256
+ subject.close
244
257
 
245
258
  expect(
246
259
  a_request(:put, breakdowns).with(body: %r|
@@ -280,38 +293,20 @@ RSpec.describe Airbrake::PerformanceNotifier do
280
293
  start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
281
294
  )
282
295
  )
296
+ subject.close
297
+
283
298
  expect(promise).to be_an(Airbrake::Promise)
284
299
  expect(promise.value).to eq('' => nil)
285
300
  end
286
301
 
287
- it "doesn't send route stats when performance stats are disabled" do
288
- Airbrake::Config.instance.merge(performance_stats: false)
289
-
290
- promise = subject.notify(
291
- Airbrake::Request.new(
292
- method: 'GET', route: '/foo', status_code: 200, start_time: Time.new
293
- )
294
- )
295
-
296
- expect(a_request(:put, routes)).not_to have_been_made
297
- expect(promise.value).to eq(
298
- 'error' => "The Performance Stats feature is disabled"
299
- )
300
- end
301
-
302
- it "doesn't send route stats when current environment is ignored" do
303
- Airbrake::Config.instance.merge(
304
- performance_stats: true, environment: 'test', ignore_environments: %w[test]
302
+ it "checks performance stat configuration" do
303
+ request = Airbrake::Request.new(
304
+ method: 'GET', route: '/foo', status_code: 200, start_time: Time.new
305
305
  )
306
-
307
- promise = subject.notify(
308
- Airbrake::Request.new(
309
- method: 'GET', route: '/foo', status_code: 200, start_time: Time.new
310
- )
311
- )
312
-
313
- expect(a_request(:put, routes)).not_to have_been_made
314
- expect(promise.value).to eq('error' => "current environment 'test' is ignored")
306
+ expect(Airbrake::Config.instance).to receive(:check_performance_options)
307
+ .with(request).and_return(Airbrake::Promise.new)
308
+ subject.notify(request)
309
+ subject.close
315
310
  end
316
311
 
317
312
  it "sends environment when it's specified" do
@@ -325,6 +320,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
325
320
  start_time: Time.new
326
321
  )
327
322
  )
323
+ subject.close
324
+
328
325
  expect(
329
326
  a_request(:put, routes).with(
330
327
  body: /\A{"routes":\[.+\],"environment":"test"}\z/x
@@ -389,6 +386,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
389
386
  start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
390
387
  )
391
388
  )
389
+ subject.close
390
+
392
391
  expect(a_request(:put, routes)).not_to have_been_made
393
392
  end
394
393
 
@@ -401,6 +400,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
401
400
  start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
402
401
  )
403
402
  )
403
+ subject.close
404
+
404
405
  expect(a_request(:put, queries)).not_to have_been_made
405
406
  end
406
407
  end
@@ -421,6 +422,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
421
422
  start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
422
423
  )
423
424
  )
425
+ subject.close
426
+
424
427
  expect(
425
428
  a_request(:put, queries).with(
426
429
  body: /\A{"queries":\[{"method":"POST","route":"\[Filtered\]"/
@@ -430,6 +433,37 @@ RSpec.describe Airbrake::PerformanceNotifier do
430
433
  end
431
434
  end
432
435
 
436
+ describe "#close" do
437
+ before do
438
+ Airbrake::Config.instance.merge(performance_stats_flush_period: 0.1)
439
+ end
440
+
441
+ after do
442
+ Airbrake::Config.instance.merge(performance_stats_flush_period: 0)
443
+ end
444
+
445
+ it "kills the background thread" do
446
+ expect_any_instance_of(Thread).to receive(:kill).and_call_original
447
+ subject.notify(
448
+ Airbrake::Query.new(
449
+ method: 'POST',
450
+ route: '/foo',
451
+ query: 'SELECT * FROM things',
452
+ start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
453
+ )
454
+ )
455
+ subject.close
456
+ end
457
+
458
+ it "logs the exit message" do
459
+ allow(Airbrake::Loggable.instance).to receive(:debug)
460
+ expect(Airbrake::Loggable.instance).to receive(:debug).with(
461
+ /performance notifier closed/
462
+ )
463
+ subject.close
464
+ end
465
+ end
466
+
433
467
  describe "#delete_filter" do
434
468
  let(:filter) do
435
469
  Class.new do
@@ -449,6 +483,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
449
483
  start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
450
484
  )
451
485
  )
486
+ subject.close
487
+
452
488
  expect(a_request(:put, routes)).to have_been_made
453
489
  end
454
490
  end
@@ -0,0 +1,158 @@
1
+ RSpec.describe Airbrake::ThreadPool do
2
+ let(:tasks) { [] }
3
+ let(:worker_size) { 1 }
4
+ let(:queue_size) { 2 }
5
+
6
+ subject do
7
+ described_class.new(
8
+ worker_size: worker_size,
9
+ queue_size: queue_size,
10
+ block: proc { |message| tasks << message }
11
+ )
12
+ end
13
+
14
+ describe "#<<" do
15
+ it "returns true" do
16
+ retval = subject << 1
17
+ subject.close
18
+ expect(retval).to eq(true)
19
+ end
20
+
21
+ it "performs work in background" do
22
+ subject << 2
23
+ subject << 1
24
+ subject.close
25
+
26
+ expect(tasks).to eq([2, 1])
27
+ end
28
+
29
+ context "when the queue is full" do
30
+ before do
31
+ allow(subject).to receive(:backlog).and_return(queue_size)
32
+ end
33
+
34
+ subject do
35
+ described_class.new(
36
+ worker_size: 1,
37
+ queue_size: 1,
38
+ block: proc { |message| tasks << message }
39
+ )
40
+ end
41
+
42
+ it "returns false" do
43
+ retval = subject << 1
44
+ subject.close
45
+ expect(retval).to eq(false)
46
+ end
47
+
48
+ it "discards tasks" do
49
+ 200.times { subject << 1 }
50
+ subject.close
51
+
52
+ expect(tasks.size).to be_zero
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#backlog" do
58
+ let(:worker_size) { 0 }
59
+
60
+ it "returns the size of the queue" do
61
+ subject << 1
62
+ expect(subject.backlog).to eq(1)
63
+ end
64
+ end
65
+
66
+ describe "#has_workers?" do
67
+ it "returns false when the thread pool is not closed, but has 0 workers" do
68
+ subject.workers.list.each do |worker|
69
+ worker.kill.join
70
+ end
71
+ expect(subject).not_to have_workers
72
+ end
73
+
74
+ it "returns false when the thread pool is closed" do
75
+ subject.close
76
+ expect(subject).not_to have_workers
77
+ end
78
+
79
+ it "respawns workers on fork()", skip: %w[jruby].include?(RUBY_ENGINE) do
80
+ pid = fork { expect(subject).to have_workers }
81
+ Process.wait(pid)
82
+ subject.close
83
+ expect(subject).not_to have_workers
84
+ end
85
+ end
86
+
87
+ describe "#close" do
88
+ context "when there's no work to do" do
89
+ it "joins the spawned thread" do
90
+ workers = subject.workers.list
91
+ expect(workers).to all(be_alive)
92
+
93
+ subject.close
94
+ expect(workers).to all(be_stop)
95
+ end
96
+ end
97
+
98
+ context "when there's some work to do" do
99
+ it "logs how many tasks are left to process" do
100
+ thread_pool = described_class.new(
101
+ worker_size: 0, queue_size: 2, block: proc {}
102
+ )
103
+
104
+ expect(Airbrake::Loggable.instance).to receive(:debug).with(
105
+ /waiting to process \d+ task\(s\)/
106
+ )
107
+ expect(Airbrake::Loggable.instance).to receive(:debug).with(/closed/)
108
+
109
+ 2.times { thread_pool << 1 }
110
+ thread_pool.close
111
+ end
112
+
113
+ it "waits until the queue gets empty" do
114
+ thread_pool = described_class.new(
115
+ worker_size: 1, queue_size: 2, block: proc {}
116
+ )
117
+
118
+ 10.times { subject << 1 }
119
+ thread_pool.close
120
+ expect(thread_pool.backlog).to be_zero
121
+ end
122
+ end
123
+
124
+ context "when it was already closed" do
125
+ it "doesn't increase the queue size" do
126
+ begin
127
+ subject.close
128
+ rescue Airbrake::Error
129
+ nil
130
+ end
131
+
132
+ expect(subject.backlog).to be_zero
133
+ end
134
+
135
+ it "raises error" do
136
+ subject.close
137
+ expect { subject.close }.to raise_error(
138
+ Airbrake::Error, 'this thread pool is closed already'
139
+ )
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "#spawn_workers" do
145
+ it "spawns alive threads in an enclosed ThreadGroup" do
146
+ expect(subject.workers).to be_a(ThreadGroup)
147
+ expect(subject.workers.list).to all(be_alive)
148
+ expect(subject.workers).to be_enclosed
149
+
150
+ subject.close
151
+ end
152
+
153
+ it "spawns exactly `workers_size` workers" do
154
+ expect(subject.workers.list.size).to eq(worker_size)
155
+ subject.close
156
+ end
157
+ end
158
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrake-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.5.1
4
+ version: 4.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Airbrake Technologies, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-29 00:00:00.000000000 Z
11
+ date: 2019-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbtree3
@@ -80,6 +80,7 @@ files:
80
80
  - lib/airbrake-ruby/stat.rb
81
81
  - lib/airbrake-ruby/sync_sender.rb
82
82
  - lib/airbrake-ruby/tdigest.rb
83
+ - lib/airbrake-ruby/thread_pool.rb
83
84
  - lib/airbrake-ruby/time_truncate.rb
84
85
  - lib/airbrake-ruby/timed_trace.rb
85
86
  - lib/airbrake-ruby/truncator.rb
@@ -92,7 +93,7 @@ files:
92
93
  - spec/config/validator_spec.rb
93
94
  - spec/config_spec.rb
94
95
  - spec/deploy_notifier_spec.rb
95
- - spec/file_cache.rb
96
+ - spec/file_cache_spec.rb
96
97
  - spec/filter_chain_spec.rb
97
98
  - spec/filters/context_filter_spec.rb
98
99
  - spec/filters/dependency_filter_spec.rb
@@ -118,8 +119,8 @@ files:
118
119
  - spec/inspectable_spec.rb
119
120
  - spec/monotonic_time_spec.rb
120
121
  - spec/nested_exception_spec.rb
122
+ - spec/notice_notifier/options_spec.rb
121
123
  - spec/notice_notifier_spec.rb
122
- - spec/notice_notifier_spec/options_spec.rb
123
124
  - spec/notice_spec.rb
124
125
  - spec/performance_breakdown_spec.rb
125
126
  - spec/performance_notifier_spec.rb
@@ -132,6 +133,7 @@ files:
132
133
  - spec/stat_spec.rb
133
134
  - spec/sync_sender_spec.rb
134
135
  - spec/tdigest_spec.rb
136
+ - spec/thread_pool_spec.rb
135
137
  - spec/time_truncate_spec.rb
136
138
  - spec/timed_trace_spec.rb
137
139
  - spec/truncator_spec.rb
@@ -187,6 +189,7 @@ test_files:
187
189
  - spec/notice_notifier_spec.rb
188
190
  - spec/time_truncate_spec.rb
189
191
  - spec/promise_spec.rb
192
+ - spec/thread_pool_spec.rb
190
193
  - spec/config/validator_spec.rb
191
194
  - spec/sync_sender_spec.rb
192
195
  - spec/ignorable_spec.rb
@@ -195,10 +198,11 @@ test_files:
195
198
  - spec/airbrake_spec.rb
196
199
  - spec/nested_exception_spec.rb
197
200
  - spec/timed_trace_spec.rb
201
+ - spec/file_cache_spec.rb
198
202
  - spec/request_spec.rb
203
+ - spec/notice_notifier/options_spec.rb
199
204
  - spec/filter_chain_spec.rb
200
205
  - spec/response_spec.rb
201
- - spec/file_cache.rb
202
206
  - spec/code_hunk_spec.rb
203
207
  - spec/fixtures/notroot.txt
204
208
  - spec/fixtures/project_root/long_line.txt
@@ -210,4 +214,3 @@ test_files:
210
214
  - spec/inspectable_spec.rb
211
215
  - spec/stashable_spec.rb
212
216
  - spec/query_spec.rb
213
- - spec/notice_notifier_spec/options_spec.rb