just_one_lock 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +2 -0
- data/Dockerfile +7 -0
- data/Gemfile +1 -0
- data/Rakefile +2 -1
- data/bin/just_one_lock +11 -11
- data/docker-compose.yml +5 -0
- data/just_one_lock.gemspec +12 -13
- data/lib/just_one_lock/base_locker.rb +3 -3
- data/lib/just_one_lock/blocking_locker.rb +3 -3
- data/lib/just_one_lock/non_blocking_locker.rb +4 -4
- data/lib/just_one_lock/version.rb +2 -1
- data/lib/just_one_lock/world.rb +3 -4
- data/lib/just_one_lock.rb +3 -2
- data/spec/just_one_lock/blocking_spec.rb +1 -1
- data/spec/just_one_lock/locking_object.rb +12 -18
- data/spec/just_one_lock/non_blocking_spec.rb +1 -1
- data/spec/just_one_lock_spec.rb +1 -0
- data/spec/spec_helper.rb +7 -6
- metadata +9 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 720c9f19a7d392419709231fb7990f0e178acad4cb33c434e9db52137e2a372d
|
4
|
+
data.tar.gz: b1d86cedb534ad6b81c5b9e5e59ca2e9cfa570fe1f3d585cffae2bfb36efe9ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 985e020c4dbf0b4c2a901d07d370fc26c4e34a4152bb8cb84855080592d0076d00612a8975f3562aceda0b33671175bc5d0557ca17def01c622267f77877a780
|
7
|
+
data.tar.gz: 1de801e3d26fa640f841f68e5960ab39a86d2b1c2669c00fbcc26d91787dccdfe17c22e412cc0edef0b4f550f5250376eccd4f7536f9a6d46ac5e5e962cc5451
|
data/.rubocop.yml
ADDED
data/Dockerfile
ADDED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/gem_tasks'
|
data/bin/just_one_lock
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'gli'
|
4
5
|
require_relative '../lib/just_one_lock'
|
@@ -10,25 +11,25 @@ include GLI::App
|
|
10
11
|
program_desc 'Just one lock runner'
|
11
12
|
version JustOneLock::VERSION
|
12
13
|
|
13
|
-
flag [:l
|
14
|
-
flag [:s
|
15
|
-
flag [:t
|
14
|
+
flag [:l, :lock_dir], default_value: '/tmp'
|
15
|
+
flag [:s, :scope]
|
16
|
+
flag [:t, :timeout], desc: 'Timeout in seconds'
|
16
17
|
|
17
18
|
desc 'Execute system command'
|
18
19
|
command :exec do |c|
|
19
|
-
c.action do |global_options,
|
20
|
+
c.action do |global_options, _options, args|
|
20
21
|
JustOneLock.world.directory = global_options[:lock_dir]
|
21
22
|
scope = global_options[:scope]
|
22
23
|
timeout = global_options[:timeout].to_f
|
23
24
|
command_to_run = args.first
|
24
25
|
|
25
|
-
if timeout > 0
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
locker = if timeout > 0
|
27
|
+
JustOneLock::BlockingLocker.new(timeout: timeout)
|
28
|
+
else
|
29
|
+
JustOneLock::NonBlockingLocker.new
|
30
|
+
end
|
30
31
|
|
31
|
-
JustOneLock
|
32
|
+
JustOneLock.prevent_multiple_executions(scope, locker) do
|
32
33
|
system command_to_run
|
33
34
|
end
|
34
35
|
end
|
@@ -37,4 +38,3 @@ end
|
|
37
38
|
default_command :exec
|
38
39
|
|
39
40
|
exit run(ARGV)
|
40
|
-
|
data/docker-compose.yml
ADDED
data/just_one_lock.gemspec
CHANGED
@@ -1,25 +1,24 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
4
|
require 'just_one_lock/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'just_one_lock'
|
8
8
|
spec.version = JustOneLock::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
9
|
+
spec.authors = ['Yury Kotov']
|
10
|
+
spec.email = ['bairkan@gmail.com']
|
11
|
+
spec.description = 'Simple solution to prevent multiple executions using flock'
|
12
|
+
spec.summary = 'Simple solution to prevent multiple executions using flock'
|
13
|
+
spec.homepage = 'http://github.com/beorc/just_one_lock'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = `git ls-files`.split(
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency "rspec", '~> 3.0'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.3'
|
22
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
24
23
|
spec.add_dependency 'gli', '~> 2.11'
|
25
24
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class JustOneLock::BaseLocker
|
2
3
|
def already_locked(scope)
|
3
4
|
msg = "Another process <#{scope}> already is running"
|
@@ -14,14 +15,13 @@ class JustOneLock::BaseLocker
|
|
14
15
|
f.truncate(f.pos)
|
15
16
|
end
|
16
17
|
|
17
|
-
def run(f, path
|
18
|
+
def run(f, path)
|
18
19
|
write_pid(f)
|
19
20
|
|
20
21
|
JustOneLock.before_lock(path, f)
|
21
|
-
result =
|
22
|
+
result = yield
|
22
23
|
JustOneLock.after_lock(path, f)
|
23
24
|
|
24
25
|
result
|
25
26
|
end
|
26
27
|
end
|
27
|
-
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'timeout'
|
2
3
|
|
3
4
|
class JustOneLock::BlockingLocker < JustOneLock::BaseLocker
|
@@ -12,8 +13,8 @@ class JustOneLock::BlockingLocker < JustOneLock::BaseLocker
|
|
12
13
|
def lock(lock_path, &block)
|
13
14
|
result = nil
|
14
15
|
|
15
|
-
File.open(lock_path, File::RDWR|File::CREAT,
|
16
|
-
Timeout
|
16
|
+
File.open(lock_path, File::RDWR | File::CREAT, 0o644) do |f|
|
17
|
+
Timeout.timeout(@timeout, JustOneLock::AlreadyLocked) { f.flock(File::LOCK_EX) }
|
17
18
|
|
18
19
|
result = run(f, lock_path, &block)
|
19
20
|
end
|
@@ -21,4 +22,3 @@ class JustOneLock::BlockingLocker < JustOneLock::BaseLocker
|
|
21
22
|
result
|
22
23
|
end
|
23
24
|
end
|
24
|
-
|
@@ -1,16 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class JustOneLock::NonBlockingLocker < JustOneLock::BaseLocker
|
2
3
|
def lock(lock_path, &block)
|
3
4
|
result = nil
|
4
5
|
|
5
|
-
File.open(lock_path, File::RDWR|File::CREAT,
|
6
|
-
if f.flock(File::LOCK_NB|File::LOCK_EX)
|
6
|
+
File.open(lock_path, File::RDWR | File::CREAT, 0o644) do |f|
|
7
|
+
if f.flock(File::LOCK_NB | File::LOCK_EX)
|
7
8
|
result = run(f, lock_path, &block)
|
8
9
|
else
|
9
|
-
|
10
|
+
raise JustOneLock::AlreadyLocked
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
13
14
|
result
|
14
15
|
end
|
15
16
|
end
|
16
|
-
|
data/lib/just_one_lock/world.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class JustOneLock::World
|
2
3
|
attr_accessor :output, :directory, :delete_files
|
3
4
|
|
@@ -12,9 +13,7 @@ class JustOneLock::World
|
|
12
13
|
paths_to_delete = []
|
13
14
|
|
14
15
|
@files.each do |path, f|
|
15
|
-
if File.
|
16
|
-
paths_to_delete << path
|
17
|
-
end
|
16
|
+
paths_to_delete << path if File.exist?(path) && f.closed?
|
18
17
|
end
|
19
18
|
|
20
19
|
paths_to_delete.each do |path|
|
@@ -27,7 +26,7 @@ class JustOneLock::World
|
|
27
26
|
@files[name] = file
|
28
27
|
end
|
29
28
|
|
30
|
-
def after_lock(
|
29
|
+
def after_lock(_name, _file)
|
31
30
|
delete_unlocked_files if delete_files
|
32
31
|
end
|
33
32
|
|
data/lib/just_one_lock.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'just_one_lock/version'
|
2
3
|
require 'just_one_lock/world'
|
3
4
|
require 'just_one_lock/base_locker'
|
4
5
|
require 'just_one_lock/blocking_locker'
|
5
6
|
require 'just_one_lock/non_blocking_locker'
|
6
7
|
require 'forwardable'
|
8
|
+
require 'pathname'
|
7
9
|
|
8
10
|
module JustOneLock
|
9
11
|
class AlreadyLocked < StandardError; end
|
@@ -22,7 +24,7 @@ module JustOneLock
|
|
22
24
|
locker = JustOneLock::NonBlockingLocker.new,
|
23
25
|
&block
|
24
26
|
)
|
25
|
-
scope_name = scope.
|
27
|
+
scope_name = scope.tr(':', '_')
|
26
28
|
lock_path = File.join(world.directory, scope_name + '.lock')
|
27
29
|
|
28
30
|
begin
|
@@ -32,4 +34,3 @@ module JustOneLock
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'spec_helper'
|
2
3
|
|
3
4
|
shared_examples 'a locking object' do
|
@@ -17,7 +18,6 @@ shared_examples 'a locking object' do
|
|
17
18
|
it 'returns value returned by block' do
|
18
19
|
Dir.mktmpdir do |lock_dir|
|
19
20
|
lockpath = File.join(lock_dir, 'sample.lock')
|
20
|
-
answer = 0
|
21
21
|
|
22
22
|
answer = locker.lock lockpath do
|
23
23
|
42
|
@@ -67,10 +67,8 @@ shared_examples 'a locking object' do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
Timeout
|
71
|
-
while locked == false
|
72
|
-
sleep 0.1
|
73
|
-
end
|
70
|
+
Timeout.timeout(1) do
|
71
|
+
sleep 0.1 while locked == false
|
74
72
|
end
|
75
73
|
|
76
74
|
expect do
|
@@ -88,27 +86,25 @@ shared_examples 'a locking object' do
|
|
88
86
|
|
89
87
|
it 'should unblock files when killing processes' do
|
90
88
|
lockpath = Tempfile.new(['sample', '.lock']).path
|
91
|
-
|
89
|
+
_dir, scope = dir_and_scope(lockpath)
|
92
90
|
|
93
|
-
pid = fork
|
94
|
-
JustOneLock
|
91
|
+
pid = fork do
|
92
|
+
JustOneLock.prevent_multiple_executions(scope, locker) do
|
95
93
|
sleep 10
|
96
94
|
end
|
97
|
-
|
95
|
+
end
|
98
96
|
|
99
|
-
Timeout
|
100
|
-
|
101
|
-
sleep 0.1
|
102
|
-
end
|
97
|
+
Timeout.timeout(1) do
|
98
|
+
sleep 0.1 until File.exist?(lockpath)
|
103
99
|
end
|
104
100
|
|
105
101
|
answer = 0
|
106
102
|
|
107
|
-
thread = Thread.new
|
108
|
-
JustOneLock
|
103
|
+
thread = Thread.new do
|
104
|
+
JustOneLock.prevent_multiple_executions(scope, locker) do
|
109
105
|
answer += 42
|
110
106
|
end
|
111
|
-
|
107
|
+
end
|
112
108
|
|
113
109
|
expect(answer).to eq(0)
|
114
110
|
Process.kill(9, pid)
|
@@ -152,5 +148,3 @@ shared_examples 'a locking object' do
|
|
152
148
|
expect(File.exist?(filename)).to eq(true)
|
153
149
|
end
|
154
150
|
end
|
155
|
-
|
156
|
-
|
data/spec/just_one_lock_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# Helper because File.write won't work for older Ruby
|
2
3
|
def write(filename, contents)
|
3
4
|
File.open(filename.to_s, 'w') { |f| f.write(contents) }
|
@@ -12,13 +13,13 @@ def dir_and_scope(lockpath)
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def parallel(n = 2, lockpath: Tempfile.new(['sample', '.lock']).path, &block)
|
15
|
-
Timeout
|
16
|
+
Timeout.timeout(5) do
|
16
17
|
dir, scope = dir_and_scope(lockpath)
|
17
18
|
JustOneLock.world.directory = dir
|
18
19
|
|
19
20
|
(1..n).map do
|
20
21
|
Thread.new do
|
21
|
-
JustOneLock
|
22
|
+
JustOneLock.prevent_multiple_executions(scope, locker, &block)
|
22
23
|
end
|
23
24
|
end.map(&:join)
|
24
25
|
end
|
@@ -27,14 +28,14 @@ def parallel(n = 2, lockpath: Tempfile.new(['sample', '.lock']).path, &block)
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def parallel_forks(n = 2, lockpath: Tempfile.new(['sample', '.lock']).path, &block)
|
30
|
-
Timeout
|
31
|
+
Timeout.timeout(5) do
|
31
32
|
dir, scope = dir_and_scope(lockpath)
|
32
33
|
JustOneLock.world.directory = dir
|
33
34
|
|
34
35
|
(1..n).map do
|
35
|
-
fork
|
36
|
-
JustOneLock
|
37
|
-
|
36
|
+
fork do
|
37
|
+
JustOneLock.prevent_multiple_executions(scope, locker, &block)
|
38
|
+
end
|
38
39
|
end.map do |pid|
|
39
40
|
Process.waitpid(pid)
|
40
41
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: just_one_lock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yury Kotov
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.3'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.3'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: rake
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -76,12 +62,15 @@ extra_rdoc_files: []
|
|
76
62
|
files:
|
77
63
|
- ".gitignore"
|
78
64
|
- ".rspec"
|
65
|
+
- ".rubocop.yml"
|
66
|
+
- Dockerfile
|
79
67
|
- Gemfile
|
80
68
|
- Gemfile.lock
|
81
69
|
- LICENSE
|
82
70
|
- README.md
|
83
71
|
- Rakefile
|
84
72
|
- bin/just_one_lock
|
73
|
+
- docker-compose.yml
|
85
74
|
- just_one_lock.gemspec
|
86
75
|
- lib/just_one_lock.rb
|
87
76
|
- lib/just_one_lock/base_locker.rb
|
@@ -98,7 +87,7 @@ homepage: http://github.com/beorc/just_one_lock
|
|
98
87
|
licenses:
|
99
88
|
- MIT
|
100
89
|
metadata: {}
|
101
|
-
post_install_message:
|
90
|
+
post_install_message:
|
102
91
|
rdoc_options: []
|
103
92
|
require_paths:
|
104
93
|
- lib
|
@@ -113,9 +102,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
102
|
- !ruby/object:Gem::Version
|
114
103
|
version: '0'
|
115
104
|
requirements: []
|
116
|
-
|
117
|
-
|
118
|
-
signing_key:
|
105
|
+
rubygems_version: 3.5.3
|
106
|
+
signing_key:
|
119
107
|
specification_version: 4
|
120
108
|
summary: Simple solution to prevent multiple executions using flock
|
121
109
|
test_files:
|