just_one_lock 0.0.1 → 0.0.2

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: bd505c4500de6a9d5ac9fca007c2d204bfe2f6a5
4
- data.tar.gz: 2817838753a95afe43173d5e867adfb8f9006d8d
3
+ metadata.gz: 4555943b102ddd4bac3f2c732d54194126999e29
4
+ data.tar.gz: 56f6671b415251bb76ee48aa37b68155dcf2bfc4
5
5
  SHA512:
6
- metadata.gz: 661c30672498de83b0380075cb0629e9d003ae132c41f906b3a90a171adfb6a0037f95f3fed7720a21fb16a08cddd545701cd26d4a6f4d7aee9046bffbb57439
7
- data.tar.gz: ccc5ae6dfde9a056f54d551f2084c7d6796318611ad01ee9c48fc3058ba8decdf4f750c2362128b57829df75ca36b8eec3877d903bb89990baaa066a0ea5f219
6
+ metadata.gz: 991fdcbbc3634896fb0e83a68f51fe7ffa24c90b124894a3977b5ee6779d5b76efdb3ebbd2dcce7f06a4e5a27c178ce8b973940cad8aadbf824806d6716921ab
7
+ data.tar.gz: 77d27fdd32f70e77a11b3ff915d9b3ee8fcd064505fac4ab7a968d9829529825b000bc6352788aeefc53956edff10f77c8ea038e89eac3e36f399d6022427c82
data/Gemfile.lock CHANGED
@@ -27,5 +27,5 @@ PLATFORMS
27
27
  DEPENDENCIES
28
28
  bundler (~> 1.3)
29
29
  just_one_lock!
30
- rake
31
- rspec
30
+ rake (~> 10.3)
31
+ rspec (~> 3.0)
data/lib/just_one_lock.rb CHANGED
@@ -2,22 +2,32 @@ require 'just_one_lock/version'
2
2
  require 'timeout'
3
3
 
4
4
  module JustOneLock
5
- def self.filelock(lockname, options = {}, &block)
5
+ DEFAULT_TIMEOUT = 0.01
6
+ class AlreadyLocked < StandardError; end
7
+
8
+ class NullStream
9
+ class << self
10
+ def puts(str); end
11
+ def <<(o); self; end
12
+ end
13
+ end
14
+
15
+ def self.filelock(lockname, timeout: JustOneLock::DEFAULT_TIMEOUT, &block)
6
16
  File.open(lockname, File::RDWR|File::CREAT, 0644) do |file|
7
- Timeout::timeout(options.fetch(:timeout, 60)) { file.flock(File::LOCK_EX) }
17
+ Timeout::timeout(timeout, JustOneLock::AlreadyLocked) { file.flock(File::LOCK_EX) }
18
+
8
19
  yield
9
20
  end
10
21
  end
11
22
 
12
- def self.prevent_multiple_executions(lock_dir, scope, &block)
23
+ def self.prevent_multiple_executions(lock_dir, scope, output: JustOneLock::NullStream, timeout: JustOneLock::DEFAULT_TIMEOUT, &block)
13
24
  scope_name = scope.gsub(':', '_')
14
25
  lock_path = File.join(lock_dir, scope_name + '.lock')
15
26
 
16
27
  begin
17
- return filelock(lock_path, &block)
18
- rescue Timeout::Error => e
19
- puts "Another process <#{scope}> already is running"
20
- exit(1)
28
+ return filelock(lock_path, timeout: timeout, &block)
29
+ rescue JustOneLock::AlreadyLocked => e
30
+ output.puts "Another process <#{scope}> already is running"
21
31
  end
22
32
  end
23
33
  end
@@ -1,3 +1,3 @@
1
1
  module JustOneLock
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -9,25 +9,32 @@ describe JustOneLock do
9
9
  File.open(filename.to_s, 'w') { |f| f.write(contents) }
10
10
  end
11
11
 
12
- def parallel(n = 2, templock = nil, &block)
13
- Timeout::timeout(5) do
14
- templock ||= Tempfile.new(['sample', '.lock'])
12
+ def dir_and_scope(lockpath)
13
+ path_segments = lockpath.split('/')
14
+ scope = path_segments.last
15
+ path_segments.delete scope
16
+ dir = path_segments.join('/')
17
+ [dir, scope]
18
+ end
15
19
 
20
+ def parallel(n = 2, lockpath: Tempfile.new(['sample', '.lock']).path, timeout: JustOneLock::DEFAULT_TIMEOUT, &block)
21
+ Timeout::timeout(5) do
22
+ dir, scope = dir_and_scope(lockpath)
16
23
  (1..n).map do
17
24
  Thread.new do
18
- JustOneLock.filelock(templock, &block)
25
+ JustOneLock.prevent_multiple_executions(dir, scope, timeout: timeout, &block)
19
26
  end
20
27
  end.map(&:join)
21
28
  end
22
29
  end
23
30
 
24
- def parallel_forks(n = 2, templock = nil, &block)
31
+ def parallel_forks(n = 2, lockpath: Tempfile.new(['sample', '.lock']).path, timeout: JustOneLock::DEFAULT_TIMEOUT, &block)
25
32
  Timeout::timeout(5) do
26
- templock ||= Tempfile.new(['sample', '.lock'])
33
+ dir, scope = dir_and_scope(lockpath)
27
34
 
28
35
  (1..n).map do
29
36
  fork {
30
- JustOneLock.filelock(templock, &block)
37
+ JustOneLock.prevent_multiple_executions(dir, scope, timeout: timeout, &block)
31
38
  }
32
39
  end.map do |pid|
33
40
  Process.waitpid(pid)
@@ -66,19 +73,18 @@ describe JustOneLock do
66
73
 
67
74
  parallel(2) do
68
75
  value = answer
69
- sleep 0.1
76
+ sleep(JustOneLock::DEFAULT_TIMEOUT / 2)
70
77
  answer = value + 21
71
78
  end
72
79
 
73
80
  expect(answer).to eq(42)
74
81
  end
75
82
 
76
- it 'handels high amount of concurrent tasks' do
83
+ it 'handles high amount of concurrent tasks' do
77
84
  answer = 0
78
85
 
79
86
  parallel(100) do
80
87
  value = answer
81
- sleep 0.001
82
88
  answer = value + 1
83
89
  end
84
90
 
@@ -86,33 +92,29 @@ describe JustOneLock do
86
92
  end
87
93
 
88
94
  it 'creates lock file on disk during block execution' do
89
- Dir.mktmpdir do |dir|
90
- lockpath = File.join(dir, 'sample.lock')
91
- parallel(2, lockpath) do
92
- expect(File.exist?(lockpath)).to eq(true)
93
- end
95
+ lockpath = Tempfile.new(['sample', '.lock']).path
96
+ parallel(2, lockpath: lockpath) do
97
+ expect(File.exist?(lockpath)).to eq(true)
94
98
  end
95
99
  end
96
100
 
97
101
  it 'runs in parallel without race condition' do
98
- Dir.mktmpdir do |dir|
99
- lockpath = File.join(dir, 'sample.lock')
102
+ lockpath = Tempfile.new(['sample', '.lock']).path
100
103
 
101
- answer = 0
102
-
103
- begin
104
- JustOneLock.filelock(lockpath) do
105
- raise '42'
106
- end
107
- rescue RuntimeError
108
- end
104
+ answer = 0
109
105
 
106
+ begin
110
107
  JustOneLock.filelock(lockpath) do
111
- answer += 42
108
+ raise '42'
112
109
  end
110
+ rescue RuntimeError
111
+ end
113
112
 
114
- expect(answer).to eq(42)
113
+ JustOneLock.filelock(lockpath) do
114
+ answer += 42
115
115
  end
116
+
117
+ expect(answer).to eq(42)
116
118
  end
117
119
 
118
120
  it 'times out after specified number of seconds' do
@@ -139,7 +141,7 @@ describe JustOneLock do
139
141
  JustOneLock.filelock lockpath, timeout: 0.001 do
140
142
  answer = 0
141
143
  end
142
- end.to raise_error(Timeout::Error)
144
+ end.to raise_error(JustOneLock::AlreadyLocked)
143
145
 
144
146
  expect(answer).to eq(42)
145
147
  end
@@ -153,7 +155,7 @@ describe JustOneLock do
153
155
 
154
156
  parallel_forks(6) do
155
157
  number = File.read('/tmp/number.txt').to_i
156
- sleep 0.3
158
+ sleep(JustOneLock::DEFAULT_TIMEOUT / 100)
157
159
  write('/tmp/number.txt', (number + 7).to_s)
158
160
  end
159
161
 
@@ -165,46 +167,47 @@ describe JustOneLock do
165
167
  it 'should handle heavy forking' do
166
168
  write('/tmp/number.txt', '0')
167
169
 
168
- parallel_forks(100) do
170
+ FORKS_NUMBER = 100
171
+ parallel_forks(FORKS_NUMBER, timeout: 1) do
169
172
  number = File.read('/tmp/number.txt').to_i
170
- sleep 0.001
171
173
  write('/tmp/number.txt', (number + 1).to_s)
172
174
  end
173
175
 
174
176
  number = File.read('/tmp/number.txt').to_i
175
177
 
176
- expect(number).to eq(100)
178
+ expect(number).to eq(FORKS_NUMBER)
177
179
  end
178
180
 
179
181
  it 'should unblock files when killing processes' do
180
- Dir.mktmpdir do |dir|
181
- lockpath = File.join(dir, 'sample.lock')
182
-
183
- Dir.mktmpdir do |dir|
184
- pid = fork {
185
- JustOneLock.filelock lockpath do
186
- sleep 10
187
- end
188
- }
182
+ lockpath = Tempfile.new(['sample', '.lock']).path
183
+ dir, scope = dir_and_scope(lockpath)
189
184
 
190
- sleep 0.5
185
+ Dir.mktmpdir do |dir|
186
+ pid = fork {
187
+ JustOneLock.prevent_multiple_executions(dir, scope) do
188
+ sleep 10
189
+ end
190
+ }
191
191
 
192
- answer = 0
192
+ Timeout::timeout(1) do
193
+ while !File.exist?(lockpath)
194
+ sleep 0.1
195
+ end
196
+ end
193
197
 
194
- thread = Thread.new {
195
- JustOneLock.filelock lockpath do
196
- answer += 42
197
- end
198
- }
198
+ answer = 0
199
199
 
200
- sleep 0.5
200
+ thread = Thread.new {
201
+ JustOneLock.prevent_multiple_executions(dir, scope) do
202
+ answer += 42
203
+ end
204
+ }
201
205
 
202
- expect(answer).to eq(0)
203
- Process.kill(9, pid)
204
- thread.join
206
+ expect(answer).to eq(0)
207
+ Process.kill(9, pid)
208
+ thread.join
205
209
 
206
- expect(answer).to eq(42)
207
- end
210
+ expect(answer).to eq(42)
208
211
  end
209
212
  end
210
213
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: just_one_lock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Stankiewicz, Yury Kotov