redis-helper 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9158b2e2f6026d24b0861d6a257f3edb475c1d03
4
- data.tar.gz: 2646c37f2ef7d789b4b9714127298d132b78809f
3
+ metadata.gz: c2ca31e77c5ef65597d7c6a3d85645d01b82bf27
4
+ data.tar.gz: 24d3c3c8890f4838dacfdbb0136b1e4e4a22fafc
5
5
  SHA512:
6
- metadata.gz: b8ba219bd493173ff38f407ac4fff7c41b865dbcf5cf3b5b33eaca06b428da05aa68909ecd605245ca1f8a2e4a98270af9a5c9777c8a5041cf2d5f9ab414e098
7
- data.tar.gz: 5e8f455b382c4c332c26f64dfa1c7cceafc8b17fdc4d3e5bb26ad4341d2983b06a7e29d90794cd73d610e8a7c2519d42877700766f10aa937ea271e61174ff57
6
+ metadata.gz: 0af9c99539da831f765713ab402f0c5b7a21623a7cec03703c681f4ae28362f0e9e6ac691aa335918e37f4e816312bdd28a4cf772f0dbb221cc43443af86c1cd
7
+ data.tar.gz: 0a6a4a5de54c157ab64c9a1aca82ab8b5de5e8dbaa1474d94983b24723f0b6ae8951356848b8a157880459f03cda260fca2243a00df342fb4c2cbb57c16f3946
data/.travis.yml CHANGED
@@ -1,5 +1,6 @@
1
- sudo: false
2
1
  language: ruby
3
2
  rvm:
4
3
  - 2.3.1
5
- before_install: gem install bundler -v 1.12.5
4
+ services:
5
+ - redis-server
6
+ cache: bundler
data/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Redis::Helper
2
2
 
3
+ [![Gem](https://img.shields.io/gem/v/redis-helper.svg)](https://rubygems.org/gems/redis-helper)
4
+ [![Gem](https://img.shields.io/gem/dtv/redis-helper.svg)](https://rubygems.org/gems/redis-helper)
5
+ [![Gemnasium](https://gemnasium.com/Narazaka/redis-helper.svg)](https://gemnasium.com/Narazaka/redis-helper)
6
+ [![Inch CI](http://inch-ci.org/github/Narazaka/redis-helper.svg)](http://inch-ci.org/github/Narazaka/redis-helper)
7
+ [![Travis Build Status](https://travis-ci.org/Narazaka/redis-helper.svg)](https://travis-ci.org/Narazaka/redis-helper)
8
+ [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/Narazaka/redis-helper?svg=true)](https://ci.appveyor.com/project/Narazaka/redis-helper)
9
+
3
10
  Redisを扱うクラスで利用するモジュール
4
11
 
5
12
  Redis::Objectsがmulti使えないとかアレっていう [@i2bskn](https://github.com/i2bskn) さん等の想いのカケラ。
data/appveyor.yml ADDED
@@ -0,0 +1,31 @@
1
+ version: "{build}"
2
+ branches:
3
+ except:
4
+ - gh-pages
5
+ install:
6
+ # redis
7
+ - nuget install redis-64 -excludeversion
8
+ - redis-64\tools\redis-server.exe --service-install
9
+ - redis-64\tools\redis-server.exe --service-start
10
+ # ruby
11
+ - set RUBY_HOME=C:\Ruby%ruby_version%
12
+ - set PATH=%RUBY_HOME%\bin;%PATH%
13
+ - |
14
+ %RUBY_HOME%\DevKit\devkitvars.bat
15
+ - ruby --version
16
+ - gem --version
17
+ - gem update --system
18
+ - gem install bundler --no-document
19
+ - bundle --version
20
+ - bundle config --local path vendor/bundle
21
+ - bundle install
22
+ test_script:
23
+ - bundle exec rake spec
24
+ build: off
25
+ deploy: off
26
+ environment:
27
+ matrix:
28
+ - ruby_version: 23
29
+ - ruby_version: 23-x64
30
+ cache:
31
+ - vendor/bundle
data/bin/console CHANGED
@@ -2,13 +2,6 @@
2
2
 
3
3
  require "bundler/setup"
4
4
  require "redis/helper"
5
+ require "pry"
5
6
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
7
+ Pry.start
data/lib/redis/helper.rb CHANGED
@@ -2,6 +2,7 @@ require "redis"
2
2
  require "active_support"
3
3
  require "active_support/core_ext/object/blank"
4
4
  require "active_support/core_ext/numeric/time"
5
+ require "redis/helper/lock"
5
6
  require "redis/helper/version"
6
7
 
7
8
  # Redisを扱うクラスで利用するモジュール
@@ -30,11 +31,14 @@ class Redis
30
31
  module Helper
31
32
  # 正しくない固有キー(固有キー値が空?)
32
33
  class UnknownUniqueValue < StandardError; end
34
+ class LockTimeout < StandardError; end
33
35
 
34
36
  # デフォルトの固有キー名
35
37
  DEFAULT_UNIQUE_ATTR_NAME = :id
36
38
  # redisキーの区切り文字
37
39
  REDIS_KEY_DELIMITER = ":".freeze
40
+ # ロックを取得に利用する接尾辞
41
+ LOCK_POSTFIX = "lock".freeze
38
42
 
39
43
  def self.included(klass)
40
44
  klass.extend ClassMethods
@@ -57,6 +61,14 @@ class Redis
57
61
  end
58
62
  end
59
63
  end
64
+
65
+ # 特定のkeyをbaseにしたロックをかけてブロック内の処理を実行
66
+ # @param [String] base_key ロックを取得するリソースのkey
67
+ # @yield ロック中に実行する処理のブロック
68
+ def lock(base_key, &block)
69
+ lock_key = [base_key, LOCK_POSTFIX].compact.join(REDIS_KEY_DELIMITER)
70
+ ::Redis::Helper::Lock.new(redis, lock_key).lock(&block)
71
+ end
60
72
  end
61
73
 
62
74
  # instance固有のkeyとattr_nameからkeyを生成する
@@ -100,5 +112,16 @@ class Redis
100
112
  def redis
101
113
  self.class.redis
102
114
  end
115
+
116
+ # 特定のkeyをbaseにしたロックをかけてブロック内の処理を実行
117
+ # @example
118
+ # lock(attr_key(:foo)) {
119
+ # # some processing
120
+ # }
121
+ # @param [String] base_key ロックを取得するリソースのkey
122
+ # @yield ロック中に実行する処理のブロック
123
+ def lock(base_key, &block)
124
+ self.class.lock(base_key, &block)
125
+ end
103
126
  end
104
127
  end
@@ -0,0 +1,80 @@
1
+ class Redis
2
+ module Helper
3
+ class Lock
4
+ # ロック取得のタイムアウト(sec)
5
+ DEFAULT_TIMEOUT = 5
6
+
7
+ def initialize(redis, lock_key, options = {})
8
+ @redis = redis
9
+ @lock_key = lock_key
10
+ @options = options
11
+ @locked_by_self = false
12
+ end
13
+
14
+ # ロックをかけてブロック内の処理を実行
15
+ # @yield ロック中に実行する処理のブロック
16
+ def lock
17
+ raise ArgumentError unless block_given?
18
+ if Thread.current[@lock_key]
19
+ yield
20
+ else
21
+ begin
22
+ Thread.current[@lock_key] = true
23
+ try_lock!(Time.now.to_f)
24
+ yield
25
+ ensure
26
+ unlock
27
+ Thread.current[@lock_key] = nil
28
+ end
29
+ end
30
+ end
31
+
32
+ # ロックを開放
33
+ # (自身でかけたロックの場合のみ開放する)
34
+ def unlock
35
+ if @locked_by_self
36
+ @redis.del(@lock_key)
37
+ @locked_by_self = false
38
+ end
39
+ end
40
+
41
+ private
42
+ # ロックを取得
43
+ # @param [Float] start ロック取得開始時間のUNIXタイムスタンプ
44
+ # @yield ロック中に実行する処理のブロック
45
+ # @raise [Redis::Helper::LockTimeout] ロックの取得に失敗した
46
+ def try_lock!(start)
47
+ loop do
48
+ if @redis.setnx(@lock_key, expiration)
49
+ @locked_by_self = true
50
+ break
51
+ end
52
+
53
+ current = @redis.get(@lock_key).to_f
54
+ if current < Time.now.to_f
55
+ old = @redis.getset(@lock_key, expiration).to_f
56
+ if old < Time.now.to_f
57
+ @locked_by_self = true
58
+ break
59
+ end
60
+ end
61
+
62
+ Kernel.sleep(0.1)
63
+ raise ::Redis::Helper::LockTimeout if (Time.now.to_f - start) > timeout
64
+ end
65
+ end
66
+
67
+ # ロックの有効期限
68
+ # @return [Float] 有効期限(UNIXタイムスタンプ)
69
+ def expiration
70
+ (Time.now + timeout).to_f
71
+ end
72
+
73
+ # ロック取得と取得したロックがタイムアウトするまでの時間
74
+ # @return [Float] タイムアウト時間(sec)
75
+ def timeout
76
+ @timeout ||= (@options[:timeout] || DEFAULT_TIMEOUT).to_f
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,6 +1,6 @@
1
1
  class Redis
2
2
  module Helper
3
3
  # バージョン
4
- VERSION = "1.1.0".freeze
4
+ VERSION = "1.2.0".freeze
5
5
  end
6
6
  end
data/redis-helper.gemspec CHANGED
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "yard"
31
31
  spec.add_development_dependency "simplecov"
32
32
  spec.add_development_dependency "onkcop"
33
+ spec.add_development_dependency "pry"
33
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Narazaka
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-17 00:00:00.000000000 Z
11
+ date: 2017-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  description:
126
140
  email:
127
141
  - info@narazaka.net
@@ -137,9 +151,11 @@ files:
137
151
  - LICENSE.txt
138
152
  - README.md
139
153
  - Rakefile
154
+ - appveyor.yml
140
155
  - bin/console
141
156
  - bin/setup
142
157
  - lib/redis/helper.rb
158
+ - lib/redis/helper/lock.rb
143
159
  - lib/redis/helper/version.rb
144
160
  - redis-helper.gemspec
145
161
  homepage: https://github.com/Narazaka/redis-helper