Skip to content
This repository was archived by the owner on Oct 28, 2020. It is now read-only.

Commit 7296ea0

Browse files
author
v.promzelev
committed
safe and unsafe method analyse
1 parent ba51cda commit 7296ea0

File tree

4 files changed

+89
-14
lines changed

4 files changed

+89
-14
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ Or install it yourself as:
2323

2424
Just place it somewhere in your app:
2525
```ruby
26-
ActiveRecord::OverflowSignalizer.new.analyse!
26+
ActiveRecord::OverflowSignalizer.new.analyse
2727
```
2828

2929
By default it checks all models in your application and logs if some primary key will overflow soon or overflowed.
30+
Also you can use unsafe method `#analyse!`, so it will raise error.
3031

3132
You can place it in some job and perform it by [clockwork](https://github.com/adamwiggins/clockwork)
3233
or just run it when app starts in a separate thread.

lib/activerecord/overflow_signalizer.rb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
module ActiveRecord
55
class OverflowSignalizer
6+
class Overflow < StandardError; end
7+
68
class UnsupportedType < StandardError
79
attr_reader :type
810

@@ -33,11 +35,17 @@ def analyse!
3335
pk = model.columns.select { |c| c.name == model.primary_key }.first
3436
max = MAX_VALUE.fetch(pk.sql_type) { |type| raise UnsupportedType, type }
3537
if overflow_soon?(max, model)
36-
signalize(table, model.last.public_send(pk.name), max)
38+
raise Overflow, overflow_message(table, model.last.public_send(pk.name), max)
3739
end
3840
end
3941
end
4042

43+
def analyse
44+
analyse!
45+
rescue Overflow => e
46+
signalize(e.message)
47+
end
48+
4149
private
4250

4351
def overflow_soon?(max, model)
@@ -58,12 +66,15 @@ def avg(model)
5866
week_records.reduce(:+) / week_records.keep_if { |v| v > 0 }.size
5967
end
6068

61-
def signalize(table, current_value, max_value)
69+
def overflow_message(table, current_value, max_value)
6270
if current_value == max_value
63-
msg = "Primary key in table #{table} overflowed! #{current_value} from #{max_value}"
71+
"Primary key in table #{table} overflowed! #{current_value} from #{max_value}"
6472
else
65-
msg = "Primary key in table #{table} will overflow soon! #{current_value} from #{max_value}"
73+
"Primary key in table #{table} will overflow soon! #{current_value} from #{max_value}"
6674
end
75+
end
76+
77+
def signalize(msg)
6778
if @logger && @logger.respond_to?(:warn)
6879
@logger.warn(msg)
6980
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module ActiveRecord
22
class OverflowSignalizer
3-
VERSION = '0.1.1'.freeze
3+
VERSION = '1.0.0'.freeze
44
end
55
end

spec/activerecord/overflow_signalizer_spec.rb

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,69 @@
66
end
77

88
describe '#analyse!' do
9+
context 'raise exception' do
10+
subject { described_class.new(models: [TestIntModel], days_count: 10) }
11+
12+
context 'empty table' do
13+
it { expect { subject.analyse! }.not_to raise_error }
14+
end
15+
16+
context 'not empty table' do
17+
let(:max_int) { 2_147_483_647 }
18+
let(:day) { 24 * 60 * 60 }
19+
let(:today) { Time.now }
20+
21+
context 'overflow far' do
22+
before do
23+
(1..7).each do |t|
24+
TestIntModel.create!(created_at: today - day * t, updated_at: today - day * t)
25+
end
26+
end
27+
28+
after do
29+
TestIntModel.connection.execute(%Q{ALTER SEQUENCE "int_test_id_seq" RESTART WITH 1;})
30+
TestIntModel.destroy_all
31+
end
32+
33+
it { expect { subject.analyse! }.not_to raise_error }
34+
end
35+
36+
context 'overflow soon' do
37+
before do
38+
TestIntModel.connection.execute(%Q{ALTER SEQUENCE "int_test_id_seq" RESTART WITH #{max_int - 16};})
39+
(1..7).each do |t|
40+
TestIntModel.create!(created_at: today - day * t, updated_at: today - day * t)
41+
end
42+
end
43+
44+
after do
45+
TestIntModel.connection.execute(%Q{ALTER SEQUENCE "int_test_id_seq" RESTART WITH 1;})
46+
TestIntModel.destroy_all
47+
end
48+
49+
it { expect { subject.analyse! }.to raise_error(described_class::Overflow) }
50+
end
51+
52+
context 'overflowed' do
53+
before do
54+
TestIntModel.connection.execute(%Q{ALTER SEQUENCE "int_test_id_seq" RESTART WITH #{max_int - 6};})
55+
(1..7).each do |t|
56+
TestIntModel.create!(created_at: today - day * t, updated_at: today - day * t)
57+
end
58+
end
59+
60+
after do
61+
TestIntModel.connection.execute(%Q{ALTER SEQUENCE "int_test_id_seq" RESTART WITH 1;})
62+
TestIntModel.destroy_all
63+
end
64+
65+
it { expect { subject.analyse! }.to raise_error(described_class::Overflow) }
66+
end
67+
end
68+
end
69+
end
70+
71+
describe '#analyse' do
972
context 'signalize to logger' do
1073
let!(:logger) { double(:logger, warn: true) }
1174

@@ -14,7 +77,7 @@
1477
context 'empty table' do
1578
it 'doesnt log anything' do
1679
expect(logger).not_to receive(:warn)
17-
subject.analyse!
80+
subject.analyse
1881
end
1982
end
2083

@@ -37,7 +100,7 @@
37100

38101
it 'doesnt log anything' do
39102
expect(logger).not_to receive(:warn)
40-
subject.analyse!
103+
subject.analyse
41104
end
42105
end
43106

@@ -57,7 +120,7 @@
57120
it 'log about owerflow' do
58121
expect(logger).to receive(:warn)
59122
.with("Primary key in table #{TestIntModel.table_name} will overflow soon! #{TestIntModel.last.id} from #{max_int}")
60-
subject.analyse!
123+
subject.analyse
61124
end
62125
end
63126

@@ -77,7 +140,7 @@
77140
it 'log about owerflow' do
78141
expect(logger).to receive(:warn)
79142
.with("Primary key in table #{TestIntModel.table_name} overflowed! #{TestIntModel.last.id} from #{max_int}")
80-
subject.analyse!
143+
subject.analyse
81144
end
82145
end
83146
end
@@ -91,7 +154,7 @@
91154
context 'empty table' do
92155
it 'doesnt log anything' do
93156
expect(signalizer).not_to receive(:signalize)
94-
subject.analyse!
157+
subject.analyse
95158
end
96159
end
97160

@@ -114,7 +177,7 @@
114177

115178
it 'doesnt log anything' do
116179
expect(signalizer).not_to receive(:signalize)
117-
subject.analyse!
180+
subject.analyse
118181
end
119182
end
120183

@@ -134,7 +197,7 @@
134197
it 'log about owerflow' do
135198
expect(signalizer).to receive(:signalize)
136199
.with("Primary key in table #{TestIntModel.table_name} will overflow soon! #{TestIntModel.last.id} from #{max_int}")
137-
subject.analyse!
200+
subject.analyse
138201
end
139202
end
140203

@@ -154,7 +217,7 @@
154217
it 'log about owerflow' do
155218
expect(signalizer).to receive(:signalize)
156219
.with("Primary key in table #{TestIntModel.table_name} overflowed! #{TestIntModel.last.id} from #{max_int}")
157-
subject.analyse!
220+
subject.analyse
158221
end
159222
end
160223
end

0 commit comments

Comments
 (0)