with_lock 0.0.4.alpha
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 +15 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +26 -0
- data/README.md +45 -0
- data/Rakefile +9 -0
- data/config/with_lock.local.yml +3 -0
- data/config/with_lock.yml +3 -0
- data/lib/with_lock.rb +89 -0
- data/lib/with_lock/client.rb +76 -0
- data/lib/with_lock/server.rb +119 -0
- data/lib/with_lock/version.rb +4 -0
- data/script/with_lock +37 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/echo_pid.sh +2 -0
- data/spec/support/get_lock.rb +21 -0
- data/spec/with_lock_spec.rb +130 -0
- data/with_lock.gemspec +23 -0
- metadata +94 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OTIxODdiOTM5NjRiZGEwMWRmYTE3NDJiMDEyMmQ5N2NiZWNhNTRiOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NDNkNjI2MDUxMmZhYmE3OWNmZThiOTI5NzMzNjgzOTFlOTU0NTNlMQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MDNhYTE5YTI3ZTE3ZWJhMTY4ODNlNWExNjI4YTQ2Y2ExNjM3NjVkM2M4OTk1
|
10
|
+
ODlhMmM4MTNlNzEyOGZkZjVjMzIyODcwZWNjMDc5NGRjM2MxOTlmYTFmZGE0
|
11
|
+
ZTBjNmFlOGRjZDgwZGU0MjA2NDNhZTJjZTc2MThjN2FkM2FjZWY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NzQzMWRhZTE5YjFlZDkyODFhY2FmNzRlODdkYzcxMmQyZWFhMWI3YjgzYWI3
|
14
|
+
NThiMjNlNDExYjkzYjZmM2FiMzAyZTc0Y2M1ZjE2ZWNjMWU5NDQ5NzFmNjU3
|
15
|
+
OTFmMWY3NTZiYmRmOTgwYmFkNGFmMmU3N2Y4MzFhYzRmYmExYzY=
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
with_lock (0.0.4.alpha)
|
5
|
+
daemons
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
daemons (1.1.9)
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
rspec (2.8.0)
|
13
|
+
rspec-core (~> 2.8.0)
|
14
|
+
rspec-expectations (~> 2.8.0)
|
15
|
+
rspec-mocks (~> 2.8.0)
|
16
|
+
rspec-core (2.8.0)
|
17
|
+
rspec-expectations (2.8.0)
|
18
|
+
diff-lcs (~> 1.1.2)
|
19
|
+
rspec-mocks (2.8.0)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
rspec
|
26
|
+
with_lock!
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# WithLock
|
2
|
+
|
3
|
+
Provides a DRb service to provide locking across a distributed ruby application.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add to your Gemfile and run the `bundle` command to install it.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem "with_lock", git: 'https://github.com/chrisboy333/with_lock.git'
|
11
|
+
```
|
12
|
+
|
13
|
+
**Tested under Ruby 1.9.3.**
|
14
|
+
|
15
|
+
Add script and config files to your project(from console):
|
16
|
+
```ruby
|
17
|
+
WithLock.setup
|
18
|
+
```
|
19
|
+
In the configuration file you can change some settings if you like ... it defaults to using the following... where 'scope' is the application directory name with rails environment appended(if present):
|
20
|
+
url: druby://loclahost:9999
|
21
|
+
scope: <%= File.basename(File.expand_path('.')) %><%= ":#{Rails.env}" if defined?(Rails) %>
|
22
|
+
directory: tmp
|
23
|
+
|
24
|
+
The scope is used to let different applications use the same drb server ... or different parts of an app acquire the same named locks(not that I think this latter is a great idea) ...
|
25
|
+
|
26
|
+
Start/Stop the service from ruby
|
27
|
+
```ruby
|
28
|
+
WithLock::Server.start_service
|
29
|
+
WithLock::Server.stop_service
|
30
|
+
```
|
31
|
+
Start/Stop service from
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
A "with_lock()" function is provided globally to wrap with_lock sections of code.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
with_lock('lock_name') do
|
38
|
+
puts "This is something only I can do right now, provided others are using the locks!"
|
39
|
+
end
|
40
|
+
```
|
41
|
+
## Development
|
42
|
+
|
43
|
+
Questions or problems? Please post them on the [issue tracker](https://github.com/chrisboy333/with_lock/issues). You can contribute changes by forking the project and submitting a pull request. You can ensure the tests passing by running `bundle` and `rake`.
|
44
|
+
|
45
|
+
This gem is created by Christopher Hauboldt and is under the MIT License.
|
data/Rakefile
ADDED
data/lib/with_lock.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require "with_lock/version"
|
2
|
+
require 'erb'
|
3
|
+
require 'yaml'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
module WithLock
|
8
|
+
class LockException < Exception
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.setup
|
12
|
+
gem_dir = File.expand_path(File.join('..','..'),__FILE__)
|
13
|
+
app_dir = File.expand_path('.')
|
14
|
+
FileUtils.cp(File.join(gem_dir,'config','with_lock.yml'),File.join(app_dir,'config','with_lock.yml'))
|
15
|
+
FileUtils.cp(File.join(gem_dir,'script','with_lock'),File.join(app_dir,'script','with_lock'))
|
16
|
+
FileUtils.chmod(0755, File.join(app_dir,'script','with_lock'))
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
module Public
|
21
|
+
def with_lock(name,timeout=5,&block)
|
22
|
+
WithLock::Client.with_lock(name,timeout) do
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Common
|
29
|
+
def logger
|
30
|
+
return @@logger if defined?(@@logger) && !@@logger.nil?
|
31
|
+
@@logger = nil
|
32
|
+
@@logger = Rails.logger if defined?(Rails)
|
33
|
+
FileUtils.mkdir_p('log') if @@logger.nil?
|
34
|
+
@@logger ||= Logger.new(File.join('log','with_lock.log'))
|
35
|
+
end
|
36
|
+
|
37
|
+
def url
|
38
|
+
settings['url']
|
39
|
+
end
|
40
|
+
|
41
|
+
def pidfile
|
42
|
+
File.join('tmp','pids','with_lock.pid')
|
43
|
+
end
|
44
|
+
|
45
|
+
def pid
|
46
|
+
File.read(pidfile).strip
|
47
|
+
rescue => e
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def running?(pid)
|
52
|
+
`ps -p#{pid} | wc -l`.to_i == 2
|
53
|
+
end
|
54
|
+
|
55
|
+
def settings_filename
|
56
|
+
File.join('config','with_lock.yml')
|
57
|
+
end
|
58
|
+
|
59
|
+
def local_settings_filename
|
60
|
+
File.join('config','with_lock.local.yml')
|
61
|
+
end
|
62
|
+
|
63
|
+
def settings
|
64
|
+
return @@settings if defined? @@settings
|
65
|
+
@@settings = default_settings
|
66
|
+
@@settings = @@settings.merge!(load_settings(settings_filename)||{}) if File.exists?(settings_filename)
|
67
|
+
@@settings.merge!(load_settings(local_settings_filename)||{}) if File.exists?(local_settings_filename)
|
68
|
+
@@settings
|
69
|
+
end
|
70
|
+
|
71
|
+
def default_settings
|
72
|
+
{
|
73
|
+
'directory' => File.join('tmp'),
|
74
|
+
'url' => "druby://localhost:9999",
|
75
|
+
'scope' => "#{File.basename(File.expand_path('.'))}#{":#{Rails.env}" if defined?(Rails)}"
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def load_settings(filename)
|
80
|
+
YAML.load(ERB.new(File.read(filename)).result)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
WithLock::Public.respond_to?(:with_lock)
|
86
|
+
|
87
|
+
require 'with_lock/server'
|
88
|
+
require 'with_lock/client'
|
89
|
+
Object.send :include, WithLock::Public
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class WithLock::Client
|
2
|
+
extend WithLock::Common
|
3
|
+
@@locker = nil
|
4
|
+
|
5
|
+
def self.scoped_name(name)
|
6
|
+
"#{scope}-#{name}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.identity
|
10
|
+
"#{`hostname`.strip}|#{$$}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.get(name,timeout=5)
|
14
|
+
locker.get(identity,scoped_name(name),timeout)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.release(name)
|
18
|
+
locker.release(identity,scoped_name(name))
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.mine?(name)
|
22
|
+
locker.mine?(identity,scoped_name(name))
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.with_lock(name, timeout=5, &block)
|
26
|
+
begin
|
27
|
+
locked = mine?(name) && increment(name)
|
28
|
+
locked ||= get(name,timeout) || raise(WithLock::LockException.new("Failed to obtain lock #{name} in #{timeout} seconds."))
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
if locker_available?
|
32
|
+
decrement(name).to_i > 0 || release(name) || logger.debug("Warning: lock #{name} not released!")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.locker_available?
|
38
|
+
locker.url
|
39
|
+
true
|
40
|
+
rescue DRb::DRbConnError => e
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.increment(name)
|
45
|
+
locker.increment(identity,scoped_name(name))
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.decrement(name)
|
49
|
+
locker.decrement(identity,scoped_name(name))
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.scope
|
53
|
+
@@scope ||= Rails.env if defined? Rails
|
54
|
+
@@scope ||= File.expand_path('.').split(File::SEPARATOR).last
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.reconnect!
|
58
|
+
DRb.stop_service
|
59
|
+
@@uri = DRb.start_service
|
60
|
+
@@locker = DRbObject.new_with_uri(url)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.locker
|
64
|
+
return @@locker if (@@locker.url rescue false)
|
65
|
+
@@locker = nil
|
66
|
+
tries = 3
|
67
|
+
while @@locker.nil? && tries > 0 do
|
68
|
+
sleep 0.2 if tries < 3
|
69
|
+
tries -= 1
|
70
|
+
reconnect!
|
71
|
+
@@locker = nil unless (@@locker.url rescue false)
|
72
|
+
end
|
73
|
+
raise WithLock::LockException.new("Couldn't connect to locker.") if @@locker.nil?
|
74
|
+
@@locker
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'daemons'
|
3
|
+
|
4
|
+
class WithLock::Server
|
5
|
+
extend WithLock::Common
|
6
|
+
|
7
|
+
def self.mutex
|
8
|
+
@@mutex ||= Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.owner_uri?(name)
|
12
|
+
locks[name][:owner]
|
13
|
+
rescue => e
|
14
|
+
''
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.owner_pid(name)
|
18
|
+
locks[name][:pid]
|
19
|
+
rescue => e
|
20
|
+
''
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.count(name)
|
24
|
+
locks[name][:count]
|
25
|
+
rescue => e
|
26
|
+
0
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.locked?(name)
|
30
|
+
!locks[name].nil?# && owner_active?(name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.mine?(owner,name)
|
34
|
+
locked?(name) && locks[name][:owner].eql?(owner)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.get(owner,name,timeout=5)
|
38
|
+
endtime = Time.now.to_f + timeout.to_f
|
39
|
+
owner_uri, owner_pid = owner.split('|')
|
40
|
+
while !mine?(owner,name) && (Time.now.to_f < endtime)
|
41
|
+
mutex.synchronize do
|
42
|
+
if !locked?(name)
|
43
|
+
locks[name] = {owner: owner, count: 1}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
sleep 0.01 unless mine?(owner,name)
|
47
|
+
end
|
48
|
+
mine?(owner,name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.release(owner,name)
|
52
|
+
if mine?(owner,name)
|
53
|
+
locks.delete(name)
|
54
|
+
true
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.increment(owner,name)
|
61
|
+
if mine?(owner,name)
|
62
|
+
locks[name][:count] += 1
|
63
|
+
end
|
64
|
+
count(name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.decrement(owner,name)
|
68
|
+
if mine?(owner,name)
|
69
|
+
locks[name][:count] -= 1
|
70
|
+
end
|
71
|
+
count(name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.locks
|
75
|
+
@@locks ||= {}
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.write_url(url)
|
79
|
+
File.open(File.join(settings['directory'],'with_lock'),'w'){|file| file.write(url)}
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.started?
|
83
|
+
pid.to_i > 0 && running?(pid)
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.daemon_settings
|
87
|
+
{
|
88
|
+
:multiple => false,
|
89
|
+
:ontop => false,
|
90
|
+
:backtrace => true,
|
91
|
+
:log_output => true,
|
92
|
+
:monitor => false,
|
93
|
+
:dir_mode => :normal,
|
94
|
+
:dir => 'tmp/pids'
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.start_service
|
99
|
+
return if started?
|
100
|
+
FileUtils.rm(pidfile) if File.exists?(pidfile)
|
101
|
+
options = daemon_settings.merge(:ARGV => ['start'])
|
102
|
+
Daemons.run_proc('with_lock', options) do
|
103
|
+
DRb.start_service(WithLock::Server::url,WithLock::Server)
|
104
|
+
DRb.thread.join
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.run_service
|
109
|
+
return if started?
|
110
|
+
DRb.start_service(WithLock::Server::url,WithLock::Server)
|
111
|
+
DRb.thread.join
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.stop_service
|
115
|
+
return unless started?
|
116
|
+
`kill #{pid}`
|
117
|
+
FileUtils.rm_f(pidfile)
|
118
|
+
end
|
119
|
+
end
|
data/script/with_lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
$:.push File.expand_path(File.join('..','..','lib'), __FILE__)
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require "bundler"
|
7
|
+
Bundler.setup
|
8
|
+
|
9
|
+
FileUtils.mkdir_p('tmp/pids') unless File.exists?('tmp/pids')
|
10
|
+
|
11
|
+
require 'with_lock'
|
12
|
+
if ARGV.include?('start')
|
13
|
+
begin
|
14
|
+
locker = WithLock::Client.locker
|
15
|
+
rescue WithLock::LockException => e
|
16
|
+
puts "Starting WithLock on #{WithLock::Server::url}!"
|
17
|
+
WithLock::Server::start_service
|
18
|
+
locker = WithLock::Client.locker
|
19
|
+
end
|
20
|
+
puts "Clearing WithLock locks!"
|
21
|
+
locker = WithLock::Client.locker
|
22
|
+
locker.locks.each_pair do |lock,data|
|
23
|
+
pid = data[:owner].split('|').last
|
24
|
+
if locker.running?(pid) || !data[:owner].include?(`hostname`.strip)
|
25
|
+
puts "Running - pid"
|
26
|
+
else
|
27
|
+
puts "Not Running - pid"
|
28
|
+
locker.release(data[:owner],lock)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
elsif ARGV.include?('stop')
|
32
|
+
puts "Stopping WithLock!"
|
33
|
+
WithLock::Server::stop_service
|
34
|
+
elsif ARGV.include?('run')
|
35
|
+
puts "Running WithLock!"
|
36
|
+
WithLock::Server::run_service
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
$:.push File.expand_path(File.join('..','..','lib'), __FILE__)
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
require "bundler"
|
8
|
+
Bundler.setup
|
9
|
+
|
10
|
+
require 'with_lock'
|
11
|
+
include WithLock::Public
|
12
|
+
|
13
|
+
begin
|
14
|
+
with_lock(ARGV[0],ARGV[1].to_f||0.5) do
|
15
|
+
sleep ARGV[2].to_f
|
16
|
+
Kernel.exit! if ARGV[3].eql?('kernel_exit')
|
17
|
+
exit(0) if ARGV[2].eql?('exit')
|
18
|
+
end
|
19
|
+
rescue WithLock::LockException => e
|
20
|
+
puts exit(1)
|
21
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.join('..','spec','spec_helper'), File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe WithLock do
|
5
|
+
describe "#settings" do
|
6
|
+
it "should have default settings" do
|
7
|
+
WithLock::Client::settings.should == {
|
8
|
+
'url' => 'druby://localhost:9999',
|
9
|
+
'directory' => 'tmp',
|
10
|
+
'scope' => 'with_lock'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#url" do
|
16
|
+
it "returns the druby url from settings" do
|
17
|
+
WithLock::Client::settings['url'].should == WithLock::Client::url
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#running(pid)" do
|
22
|
+
it "should report if given process id represents a running pid" do
|
23
|
+
WithLock::Server::running?($$).should be_true
|
24
|
+
end
|
25
|
+
it "should report if given process id doesn't represent a running pid" do
|
26
|
+
pid = `spec/support/echo_pid.sh`.to_s.strip
|
27
|
+
sleep 0.2
|
28
|
+
WithLock::Server::running?(pid).should be_false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#with_lock" do
|
33
|
+
it "should raise an exception if with_lock server not started" do
|
34
|
+
WithLock::Server.stop_service
|
35
|
+
started_trying = Time.now
|
36
|
+
while WithLock::Server.started? do
|
37
|
+
sleep 0.2
|
38
|
+
raise Exception.new("Couldn't stop server!") unless (Time.now - 3.seconds) > started_trying
|
39
|
+
end
|
40
|
+
error_message = ''
|
41
|
+
begin
|
42
|
+
with_lock('my_lock') do
|
43
|
+
"I should not get here!".should be_nil
|
44
|
+
end
|
45
|
+
rescue WithLock::LockException => e
|
46
|
+
e.message.should == "Couldn't connect to locker."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
describe "when the server is running" do
|
50
|
+
before(:all) do
|
51
|
+
`script/with_lock start`
|
52
|
+
started_trying = Time.now
|
53
|
+
while !WithLock::Server.started? do
|
54
|
+
sleep 0.2
|
55
|
+
raise Exception.new("Couldn't start server!") unless (Time.now - 3.seconds) > started_trying
|
56
|
+
end
|
57
|
+
@locker = WithLock::Client.locker
|
58
|
+
end
|
59
|
+
after(:all) do
|
60
|
+
`script/with_lock stop`
|
61
|
+
while WithLock::Server.started? do
|
62
|
+
sleep 0.1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
it "should grab the named lock if its not locked" do
|
66
|
+
with_lock('name') do
|
67
|
+
WithLock::Client.mine?('name').should be_true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
it "should not allow another process to grab the same named lock" do
|
71
|
+
system("spec/support/get_lock.rb name 0.5 10 &")
|
72
|
+
sleep 1
|
73
|
+
expect {
|
74
|
+
with_lock('name',0.5) do
|
75
|
+
end
|
76
|
+
}.to raise_exception(WithLock::LockException)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should have a counter of 1 when it first grabs the lock" do
|
80
|
+
with_lock('blarg') do
|
81
|
+
@locker.count(WithLock::Client.scoped_name('blarg')).should == 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should allow the same process to grab the same lock and increment its counter" do
|
86
|
+
with_lock('blarg') do
|
87
|
+
with_lock('blarg') do
|
88
|
+
@locker.count(WithLock::Client.scoped_name('blarg')).should == 2
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should decrement a lock's counter when it ends the block" do
|
94
|
+
with_lock('blarg') do
|
95
|
+
with_lock('blarg') do
|
96
|
+
end
|
97
|
+
@locker.count(WithLock::Client.scoped_name('blarg')).should == 1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should release the lock when the block ends" do
|
102
|
+
with_lock('blarg') do
|
103
|
+
end
|
104
|
+
@locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should release the lock if an exception closes the block" do
|
108
|
+
begin
|
109
|
+
with_lock('blarg') do
|
110
|
+
raise "Blarg!!"
|
111
|
+
end
|
112
|
+
rescue => e
|
113
|
+
end
|
114
|
+
@locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should release the lock on a clean exit" do
|
118
|
+
`spec/support/get_lock.rb blarg 0.3 exit`
|
119
|
+
sleep 0.2
|
120
|
+
@locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should release the lock on an immediate exit" do
|
124
|
+
`spec/support/get_lock.rb blarg 0.3 kernel_exit`
|
125
|
+
sleep 0.2
|
126
|
+
@locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/with_lock.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'with_lock/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "with_lock"
|
7
|
+
s.version = WithLock::VERSION
|
8
|
+
s.authors = ["Christopher Louis Hauboldt"]
|
9
|
+
s.email = ["chris@hauboldt.us"]
|
10
|
+
s.homepage = "https://github.com/chrisboy333/with_lock"
|
11
|
+
s.summary = %q{Implements named mutexes for ruby applications.}
|
12
|
+
s.description = %q{Implements named mutexes for ruby applications by creating a resource server to query for locks.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "with_lock"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rspec"
|
22
|
+
s.add_dependency "daemons"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: with_lock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4.alpha
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Louis Hauboldt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: daemons
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Implements named mutexes for ruby applications by creating a resource
|
42
|
+
server to query for locks.
|
43
|
+
email:
|
44
|
+
- chris@hauboldt.us
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- .gitignore
|
50
|
+
- .rspec
|
51
|
+
- Gemfile
|
52
|
+
- Gemfile.lock
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- config/with_lock.local.yml
|
56
|
+
- config/with_lock.yml
|
57
|
+
- lib/with_lock.rb
|
58
|
+
- lib/with_lock/client.rb
|
59
|
+
- lib/with_lock/server.rb
|
60
|
+
- lib/with_lock/version.rb
|
61
|
+
- script/with_lock
|
62
|
+
- spec/spec_helper.rb
|
63
|
+
- spec/support/echo_pid.sh
|
64
|
+
- spec/support/get_lock.rb
|
65
|
+
- spec/with_lock_spec.rb
|
66
|
+
- with_lock.gemspec
|
67
|
+
homepage: https://github.com/chrisboy333/with_lock
|
68
|
+
licenses: []
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ! '>'
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.3.1
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project: with_lock
|
86
|
+
rubygems_version: 2.2.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Implements named mutexes for ruby applications.
|
90
|
+
test_files:
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
- spec/support/echo_pid.sh
|
93
|
+
- spec/support/get_lock.rb
|
94
|
+
- spec/with_lock_spec.rb
|