just_one_lock 0.2.0 → 0.2.2
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 +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:
|