locked_process 0.0.1
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.
- data/README.md +26 -0
- data/lib/locked_process.rb +42 -0
- data/spec/lib/locked_process_spec.rb +88 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/test.rb +17 -0
- metadata +117 -0
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# LockedProcess
|
2
|
+
Locked process is a way of executing a Thread but preventing the same Thread from being executed while the first one is still running.
|
3
|
+
|
4
|
+
## Instalation
|
5
|
+
```bash
|
6
|
+
gem install 'locked_process'
|
7
|
+
```
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
```ruby
|
11
|
+
require 'locked_process'
|
12
|
+
|
13
|
+
process = LockedProcess.new('/tmp/download_images.pid') do
|
14
|
+
MyImageDownloader.new.download
|
15
|
+
end
|
16
|
+
|
17
|
+
process.execute # executes MyImageDownloader.new.download in a Thread
|
18
|
+
|
19
|
+
# if the process is still running
|
20
|
+
process.execute # raises LockedProcess::Error
|
21
|
+
|
22
|
+
```
|
23
|
+
|
24
|
+
|
25
|
+
## Author
|
26
|
+
Marcelo Jacobus
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class LockedProcess
|
4
|
+
VERSION = '0.0.1'
|
5
|
+
|
6
|
+
class Error < StandardError; end
|
7
|
+
|
8
|
+
attr_reader :pid_file
|
9
|
+
|
10
|
+
def initialize(pid_file)
|
11
|
+
unless block_given?
|
12
|
+
raise ArgumentError.new('Block must be given')
|
13
|
+
end
|
14
|
+
|
15
|
+
@process = lambda { yield }
|
16
|
+
@pid_file = pid_file
|
17
|
+
end
|
18
|
+
|
19
|
+
def pid_file_exists?
|
20
|
+
File.exists?(pid_file)
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
create_pid_file
|
25
|
+
Thread.new do
|
26
|
+
@process.call
|
27
|
+
remove_pid_file
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def create_pid_file
|
33
|
+
if pid_file_exists?
|
34
|
+
raise Error.new("Process is already running (pidfile '#{pid_file}' exists)")
|
35
|
+
end
|
36
|
+
File.open(pid_file, 'w').close
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove_pid_file
|
40
|
+
File.unlink(pid_file)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LockedProcess do
|
4
|
+
before do
|
5
|
+
system("rm -f #{pidfile}")
|
6
|
+
system("rm -f #{test_file}")
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
system("rm -f #{pidfile}")
|
11
|
+
system("rm -f #{test_file}")
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:mocked) { mock(:mocked, run: 'running') }
|
15
|
+
let(:pidfile) { '/tmp/locked_process_spec.pid' }
|
16
|
+
let(:test_file) { '/tmp/locked_process_test_file.pid' }
|
17
|
+
|
18
|
+
subject do
|
19
|
+
LockedProcess.new(pidfile) do
|
20
|
+
mocked.run('abc')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
describe "#initialize" do
|
26
|
+
context "when block is not given" do
|
27
|
+
it "raises ArgumentError" do
|
28
|
+
expect { LockedProcess.new(pidfile) }.to raise_error(ArgumentError, 'Block must be given')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#execute" do
|
34
|
+
it "creates a pid file" do
|
35
|
+
subject.execute
|
36
|
+
File.exists?(pidfile).should be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
it "raises an exception when file exists" do
|
40
|
+
subject.stub(:pid_file_exists?).and_return(true)
|
41
|
+
expect { subject.execute }.to raise_error(LockedProcess::Error, "Process is already running (pidfile '#{pidfile}' exists)")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "executes the code in a thread and removes the pid file" do
|
45
|
+
process = LockedProcess.new(pidfile) do
|
46
|
+
sleep(0.1)
|
47
|
+
File.open(test_file, 'w').close
|
48
|
+
end
|
49
|
+
|
50
|
+
process.execute
|
51
|
+
|
52
|
+
File.exists?(test_file).should be_false
|
53
|
+
File.exists?(pidfile).should be_true
|
54
|
+
sleep(0.2)
|
55
|
+
File.exists?(test_file).should be_true
|
56
|
+
File.exists?(pidfile).should be_false
|
57
|
+
end
|
58
|
+
|
59
|
+
it "executes even if the main process is gone down" do
|
60
|
+
process = LockedProcess.new(pidfile) do
|
61
|
+
sleep(0.1)
|
62
|
+
File.open(test_file, 'w').close
|
63
|
+
end
|
64
|
+
|
65
|
+
process.execute
|
66
|
+
|
67
|
+
fork do
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
File.exists?(test_file).should be_false
|
72
|
+
File.exists?(pidfile).should be_true
|
73
|
+
sleep(0.2)
|
74
|
+
File.exists?(test_file).should be_true
|
75
|
+
File.exists?(pidfile).should be_false
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#pid_file_exists?" do
|
81
|
+
it "checks whether pid file exists" do
|
82
|
+
subject.pid_file_exists?.should be_false
|
83
|
+
system("touch #{pidfile}")
|
84
|
+
subject.pid_file_exists?.should be_true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
SimpleCov.start do
|
4
|
+
add_filter "spec"
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'locked_process'
|
8
|
+
|
9
|
+
Dir["./spec/support/**/*.rb"].each {|f| require f}
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
config.filter_run :focus => true
|
14
|
+
config.run_all_when_everything_filtered = true
|
15
|
+
end
|
data/spec/test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.push File.expand_path("../../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'locked_process'
|
4
|
+
|
5
|
+
file = '/tmp/locked_process_test_file.txt'
|
6
|
+
pidfile = '/tmp/locked_process_test_file_pid.pid'
|
7
|
+
|
8
|
+
File.unlink(file) if File.exists?(file)
|
9
|
+
#File.unlink(pidfile) if File.exists?(pidfile)
|
10
|
+
|
11
|
+
process = LockedProcess.new(pidfile) do
|
12
|
+
sleep 2
|
13
|
+
File.open(file, 'w').close
|
14
|
+
sleep 2
|
15
|
+
end
|
16
|
+
|
17
|
+
process.execute
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: locked_process
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Marcelo Jacobus
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: simplecov
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard-rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rb-inotify
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Trhead process that only executes if no other thread with the same lock
|
79
|
+
file is running
|
80
|
+
email: marcelo.jacobus@gmail.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- README.md
|
86
|
+
- lib/locked_process.rb
|
87
|
+
- spec/test.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/lib/locked_process_spec.rb
|
90
|
+
homepage: https://github.com/mjacobus/locked_process
|
91
|
+
licenses: []
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 1.8.24
|
111
|
+
signing_key:
|
112
|
+
specification_version: 3
|
113
|
+
summary: Thread process with that can run only if it is unique
|
114
|
+
test_files:
|
115
|
+
- spec/test.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/lib/locked_process_spec.rb
|