visit-counter 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -34,6 +34,32 @@ module VisitCounter
34
34
  redis.set(key, 0)
35
35
  end
36
36
 
37
+ def substract(key, by)
38
+ redis.decrby(key, by)
39
+ end
40
+
41
+ def aquire_lock!(object)
42
+ redis.setnx(lock_key(object), 1)
43
+ end
44
+
45
+ def unlock!(object)
46
+ redis.del(lock_key(object))
47
+ end
48
+
49
+ def lock_key(object)
50
+ "#{object.class.name.downcase}_#{object.id}_object_cache_lock"
51
+ end
52
+
53
+ def with_lock(object, &block)
54
+ if aquire_lock!(object)
55
+ begin
56
+ yield
57
+ ensure
58
+ unlock!(object)
59
+ end
60
+ end
61
+ end
62
+
37
63
  end
38
64
  end
39
65
  end
@@ -1,3 +1,3 @@
1
1
  module VisitCounter
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -33,9 +33,13 @@ module VisitCounter
33
33
  current_count + count
34
34
  end
35
35
 
36
- def nullify_counter_cache(name)
36
+ def nullify_counter_cache(name, substract = nil)
37
37
  key = VisitCounter::Key.key(self, name)
38
- VisitCounter::Store.engine.nullify(key)
38
+ if substract
39
+ VisitCounter::Store.engine.substract(key, substract)
40
+ else
41
+ VisitCounter::Store.engine.nullify(key)
42
+ end
39
43
  end
40
44
  end
41
45
 
@@ -68,8 +72,10 @@ module VisitCounter
68
72
  end
69
73
 
70
74
  def persist(object, staged_count, diff, name)
71
- object.update_attribute(name, staged_count + diff)
72
- object.nullify_counter_cache(name)
75
+ VisitCounter::Store.engine.with_lock(object) do
76
+ object.update_attribute(name, staged_count + diff)
77
+ object.nullify_counter_cache(name, diff)
78
+ end
73
79
  end
74
80
 
75
81
  def default_threshold(method)
@@ -79,6 +85,7 @@ module VisitCounter
79
85
  0.3
80
86
  end
81
87
  end
88
+
82
89
  end
83
90
  end
84
91
  end
@@ -16,6 +16,7 @@ class DummyObject
16
16
  end
17
17
 
18
18
  VisitCounter::Store::RedisStore.redis = Redis.new(host: "localhost")
19
+ VisitCounter::Store::RedisStore.redis.flushdb
19
20
 
20
21
  describe VisitCounter do
21
22
  describe "incrementing counters" do
@@ -110,6 +111,31 @@ describe VisitCounter do
110
111
  end
111
112
  end
112
113
 
114
+ describe "locked objects" do
115
+ before :each do
116
+ @d = DummyObject.new
117
+ @d.stub!(:id).and_return(1)
118
+ @d.nullify_counter_cache(:counter)
119
+ end
120
+
121
+ it "should lock object when updating" do
122
+ VisitCounter::Store.engine.should_receive(:with_lock)
123
+ VisitCounter::Helper.persist(@d, 1, 1, :counter)
124
+ end
125
+
126
+ it "should not persist if object is locked" do
127
+ VisitCounter::Store.engine.stub!(:aquire_lock!).and_return(false)
128
+ @d.should_not_receive(:update_attribute)
129
+ VisitCounter::Helper.persist(@d, 1, 1, :counter)
130
+ end
131
+
132
+ it "should persist if object is locked" do
133
+ VisitCounter::Store.engine.stub!(:aquire_lock!).and_return(true)
134
+ @d.should_receive(:update_attribute)
135
+ VisitCounter::Helper.persist(@d, 1, 1, :counter)
136
+ end
137
+ end
138
+
113
139
  describe "overriding the getter" do
114
140
  before :all do
115
141
  DummyObject.cached_counter :counter
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: visit-counter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-06 00:00:00.000000000 Z
12
+ date: 2012-09-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec