airbrake-ruby 4.5.1 → 4.7.0

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.
@@ -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