visit-counter 0.1.0 → 0.1.1

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