redis_lock 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee826bd92ec9c79acb13dd5abd4c25cae2b58740
4
- data.tar.gz: 8111863df02cc6c004e9ae65cbdfa5106fc7eb89
3
+ metadata.gz: 3ad868ca731e9080d8c65e079d50f14718f696e7
4
+ data.tar.gz: 5c6e6dc414ed41926ffd3544db3f4f506971e225
5
5
  SHA512:
6
- metadata.gz: 658f04d297764af0e0fe29739972eacd3aebeeb43334c59d51fe070ca86e7455afa75e6c4b3ff6fe1a6b44d7327cf00ee39443295ef793a7080756dfa97d0697
7
- data.tar.gz: e7b3e9954828b0fc0d53c15b35476561ecfbf52d201e7977baeeadb4c66861bf677f495bc5334964d34a089eb148470020b42b0571953886b4280447ec35478f
6
+ metadata.gz: cd7fc6334ce0b05e4cc2d60d3bf275703e3207b84b659e3c55e222e6b1ef9ef6d630e239d5a58f70aa7dcf2d17494318f8e54bffbd6f2a406825cf136e395031
7
+ data.tar.gz: eaf6171599bc5688c6a00e8bc926b2654f4a52c514753f83eae3cd5a5a370153c660cc2879687064531e47b0c91cb033e930f0ab6fc35a4d0a5ad466301d3086
data/Gemfile CHANGED
@@ -5,4 +5,4 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5
5
  # Specify your gem's dependencies in redis_lock.gemspec
6
6
  gemspec
7
7
 
8
- gem 'contextuable'
8
+ gem 'dystruct'
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # RedisLock
2
+ **use cases:**
2
3
 
3
- Do not allow anyone to perfor de same operation while this is running.
4
- Do not perform this operation unless the previous was executed in more than 5 minutes ago.
4
+ - Do not allow anyone to perform de same operation while this is running.
5
+ - Do not perform this operation unless the previous was executed in more than 5 minutes ago.
5
6
 
6
7
  ## Installation
7
8
 
@@ -21,11 +22,41 @@ Or install it yourself as:
21
22
 
22
23
  ## Setup
23
24
 
25
+ This setup it's optional in any instance of `RedisLock` you can provide an optional
26
+ argument `:redis`.
27
+ But if you do not want to provide it in all the instances is a good shortcut to
28
+ set it here.
29
+
24
30
  ```ruby
25
31
  RedisLock.setup do |config|
32
+ # redis
33
+ # Accepts `block` (or something responding to `#call`) or `Hash`
34
+ #
35
+ # In test configuration like your `spec_helper`
36
+ # recommend `mock_redis` gem
37
+ # example:
38
+ # config.redis = -> { MockRedis.new }
39
+ #
40
+ # When using Sidekiq
41
+ # example:
42
+ # config.redis = -> { Sidekiq.redis{ |r| r } }
43
+ #
44
+ # In `Rails`
45
+ # example:
46
+ # config.redis = -> do
47
+ # if Rails.env.test?
48
+ # MockRedis.new
49
+ # elsif Rails.env.development?
50
+ # { host: '127.0.0.1', port: 6379 }
51
+ # else
52
+ # Sidekiq.redis{ |r| r }
53
+ # end
54
+ # end
26
55
  config.redis = { host: '127.0.0.1'
27
56
  port: 6379
28
57
  db: 2 }
58
+ # logger
59
+ # default: Logger.new(STDOUT)
29
60
  config.logger = Rails.logger
30
61
  end
31
62
  ```
@@ -42,20 +73,135 @@ lock.locked? #=> true
42
73
  lock.remove #=> true
43
74
  lock.locked? #=> false
44
75
  ```
45
-
76
+ __as Mutex__
46
77
  ```ruby
47
78
  lock = RedisLock.new('my_key')
48
- out = subject.perform do
49
- #no one can perform the same operation while this is running
50
- {}.tap do |t|
51
- t[:locked?] = subject.locked?
52
- end
79
+ out = lock.if_open do |l|
80
+ # no one can perform the same operation while this is running
81
+ l.set(30) # place the lock so no one else can perform this tasks
82
+ sleep 3 # Do something
83
+ l.unlock! # release the lock
84
+ :hello
53
85
  end
54
- out[:locked?] #=> true
55
- # once the block has finished releases the lock
86
+ out #=> :hello
56
87
  lock.locked? #=> false
57
88
  ```
58
89
 
90
+ __blocking for a time__
91
+
92
+ Send email to user. The User should receive only 1 email per day
93
+
94
+ ```ruby
95
+ ttl = (24 * 3600) # one day
96
+ lock = RedisLock.new("User:1-sales-products")
97
+ lock.if_open do |l|
98
+ # Send Email
99
+ l.set(ttl)
100
+ end
101
+ ```
102
+
103
+ ## Methods:
104
+
105
+ __set__
106
+ Will store the key to redis with a ttl (time to live).
107
+ args:
108
+ - ttl # default: 60
109
+ - opts # default: {}
110
+ * value (String) - default: time now
111
+ * px (true) - miliseconds instead of seconds default: false
112
+ * nk (true) - Only set the key if it does not already exist.
113
+ * xx (true) - Only set the key if it already exist.
114
+ ```ruby
115
+ lock = RedisLock.new('my_key')
116
+
117
+ lock.set(60)
118
+ lock.ttl #=> 60
119
+ lock.open? # => false
120
+ ```
121
+
122
+ _with options_
123
+
124
+ ```ruby
125
+ lock = RedisLock.new('my_key')
126
+
127
+ lock.set(60, nx: true) # only if the key does not exists
128
+ # => true (key has been stored)
129
+ lock.ttl #=> 60
130
+ lock.open? # => false
131
+ ```
132
+
133
+ Redis documentation: https://redis.io/commands/set
134
+
135
+ Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. Any previous time to live associated with the key is discarded on successful SET operation.
136
+
137
+ EX seconds -- Set the specified expire time, in seconds.
138
+ PX milliseconds -- Set the specified expire time, in milliseconds.
139
+ NX -- Only set the key if it does not already exist.
140
+ XX -- Only set the key if it already exist.
141
+
142
+
143
+ __locked?__
144
+ Returns `true` if lock is set
145
+
146
+ ```ruby
147
+ lock = RedisLock.new('my_key')
148
+ lock.set(60) # => true (key has been stored)
149
+ lock.locked? # => true
150
+ lock.remove
151
+ lock.locked? # => false
152
+ ```
153
+ _alias method:_ `exists?`
154
+
155
+ __open?__
156
+ Returns `true` if NO lock is set
157
+
158
+ ```ruby
159
+ lock = RedisLock.new('my_key')
160
+ lock.open? # => true
161
+ lock.set(60) # => true (key has been stored)
162
+ lock.open? # => false
163
+ ```
164
+ _alias method:_ `unlocked?`
165
+
166
+ __delete__
167
+ Removes the key from the Redis store
168
+
169
+ ```ruby
170
+ lock = RedisLock.new('my_key')
171
+ lock.set(60) # => true (key has been stored)
172
+ lock.locked? # => true
173
+ lock.delete
174
+ lock.locked? # => false
175
+ ```
176
+ _alias methods:_ `unlock!`,`open!`
177
+
178
+ __value__
179
+ Returns the value stored in redis
180
+
181
+ ```ruby
182
+ lock = RedisLock.new('my_key')
183
+ lock.set(60, value: 'hi there!')
184
+ lock.value # => 'hi there!'
185
+ ```
186
+ __ttl__
187
+ Returns the pending ttl (time to live)
188
+
189
+ ```ruby
190
+ lock = RedisLock.new('my_key')
191
+ lock.set(60)
192
+ lock.ttl # => 60
193
+ sleep 10
194
+ lock.ttl # => 50
195
+ ```
196
+
197
+ __having already a connection:__ _example: Sidekiq_
198
+
199
+ ```ruby
200
+ Sidekiq.redis do |connection|
201
+ lock = RedisLock.new('my_key', redis: connection)
202
+ # do something
203
+ end
204
+ ```
59
205
  ## Development
60
206
 
61
207
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,34 @@
1
+ require 'logger'
2
+ class RedisLock
3
+ class Configuration
4
+ class RedisNotSet < StandardError; end
5
+ def redis=(hash = {})
6
+ @redis = hash
7
+ end
8
+
9
+ def redis
10
+ fail RedisNotSet, "[#{self.class}] redis connection setup is not set" unless @redis
11
+ if @redis.respond_to?(:call)
12
+ return @redis.call
13
+ else
14
+ self.redis_instance = @redis
15
+ @redis_instance
16
+ end
17
+ end
18
+
19
+
20
+ def logger=(logger)
21
+ @logger = logger
22
+ end
23
+
24
+ def logger
25
+ @logger ? @logger : Logger.new(STDOUT)
26
+ end
27
+
28
+ private
29
+
30
+ def redis_instance=(args)
31
+ @redis_instance ||= Redis.new(args)
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  class RedisLock
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/redis_lock.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require 'redis'
2
2
  require "redis_lock/version"
3
- require "redis_lock/config"
3
+ require "redis_lock/configuration"
4
4
 
5
5
  class RedisLock
6
6
  attr_reader :key
7
7
 
8
8
  def self.config
9
- @config ||= Config.new
9
+ @config ||= Configuration.new
10
10
  end
11
11
 
12
12
  def self.setup
@@ -21,46 +21,67 @@ class RedisLock
21
21
  end
22
22
 
23
23
  def redis
24
- @redis ||= Redis.new(config.redis)
24
+ @redis ||= config.redis
25
25
  end
26
26
 
27
- def set(expiration_time = 600)
28
- redis.set(
29
- key,
30
- Time.now.strftime('%FT%T'),
31
- ex: expiration_time, # expires in X seconds
32
- nx: true # only if it does not exists
33
- )
27
+ # Redis SET options:
28
+ # - EX seconds -- Set the specified expire time, in seconds.
29
+ # - PX milliseconds -- Set the specified expire time, in milliseconds.
30
+ # - NX -- Only set the key if it does not already exist.
31
+ # - XX -- Only set the key if it already exist.
32
+ def set(expiration_time = 60, opts = {})
33
+ value = opts.delete(:value) || Time.now.strftime('%FT%T')
34
+ args = if opts[:px]
35
+ { px: expiration_time }
36
+ else
37
+ { ex: expiration_time }
38
+ end
39
+ redis.set(key, value, args.merge(opts)) == "OK" ? true : false
34
40
  end
35
41
 
36
- def perform(args = {}, &block)
42
+ def if_open(args = {}, &block)
37
43
  return if locked?
38
- expiration = args[:expiration] || args[:ex] || 600
39
- set(expiration)
40
- # If error occurs, we remove the lock
41
- out = _perform(&block)
42
- remove
43
- out
44
+ _perform(&block)
44
45
  end
46
+ alias_method :perform, :if_open
45
47
 
46
-
48
+ def if_locked(args = {}, &block)
49
+ return if open?
50
+ _perform(&block)
51
+ end
47
52
 
48
53
  def locked?
49
- redis.ttl(key) == -2 ? false : true
54
+ ttl == -2 ? false : true
50
55
  end
51
56
  alias_method :exists?, :locked?
52
57
 
53
- def remove
58
+ def ttl
59
+ redis.ttl(key)
60
+ end
61
+
62
+ def open?
63
+ !locked?
64
+ end
65
+ alias_method :unlocked?, :open?
66
+
67
+ def delete
54
68
  redis.del(key) == 1 ? true : false
55
69
  end
70
+ alias_method :unlock!, :delete
71
+ alias_method :open!, :delete
72
+ alias_method :remove, :delete
73
+
74
+ def value
75
+ redis.get(key)
76
+ end
56
77
 
57
78
  private
58
79
 
59
80
  def _perform(&block)
60
81
  yield self
61
82
  rescue => e
62
- config.logger.error "[RedisLock] key: `#{key}` error:"
83
+ config.logger.error "[#{self.class}] key: `#{key}` error:"
63
84
  config.logger.error e
64
- false
85
+ raise e
65
86
  end
66
87
  end
data/redis_lock.gemspec CHANGED
@@ -23,5 +23,6 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.15"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_development_dependency "rspec", "~> 3.6"
26
+ spec.add_development_dependency "mock_redis", "~> 0.17"
26
27
  spec.add_dependency "redis", "~> 3"
27
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_lock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artur Pañach
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-29 00:00:00.000000000 Z
11
+ date: 2017-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mock_redis
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.17'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.17'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: redis
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +95,7 @@ files:
81
95
  - bin/console
82
96
  - bin/setup
83
97
  - lib/redis_lock.rb
84
- - lib/redis_lock/config.rb
98
+ - lib/redis_lock/configuration.rb
85
99
  - lib/redis_lock/version.rb
86
100
  - redis_lock.gemspec
87
101
  homepage: https://github.com/arturictus/redis_lock.git
@@ -103,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
117
  version: '0'
104
118
  requirements: []
105
119
  rubyforge_project:
106
- rubygems_version: 2.4.5
120
+ rubygems_version: 2.2.3
107
121
  signing_key:
108
122
  specification_version: 4
109
123
  summary: Lock with redis
@@ -1,20 +0,0 @@
1
- class RedisLock
2
- class Config
3
- def redis=(hash = {})
4
- @redis = hash
5
- end
6
-
7
- def redis
8
- fail "[RedisLock::Config] redis connection setup is not set" unless @redis
9
- @redis
10
- end
11
-
12
- def logger=(logger)
13
- @logger = logger
14
- end
15
-
16
- def logger
17
- @logger ? @logger : Logger.new(STDOUT)
18
- end
19
- end
20
- end