localjob 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -35
- data/lib/localjob/sysv_adapter.rb +15 -28
- data/lib/localjob/version.rb +1 -1
- data/lib/localjob/worker.rb +53 -24
- data/lib/localjob.rb +7 -17
- data/localjob.gemspec +2 -2
- data/test/localjob_test.rb +1 -9
- data/test/mock_adapter.rb +1 -0
- data/test/sysv_adapter_test.rb +23 -0
- data/test/test_helper.rb +5 -17
- data/test/worker_test.rb +29 -34
- metadata +34 -22
- data/ext/mkrf_conf.rb +0 -4
- data/lib/localjob/channel.rb +0 -18
- data/lib/localjob/linux_adapter.rb +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d66cdf9e9ef8c26230cc76e00a40964249c62db
|
4
|
+
data.tar.gz: cdb1b11bacb52f1d9cdc75dec508b4fbe61ee743
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9fbe02975d57dd69a328050f4f04a1f3e07312714f6bd5ac8a6fdcbddf02ba55905a11a4a82e677a49524e2b1552f0da0a16d0090f9fc2adf433d8a547f45c5d
|
7
|
+
data.tar.gz: 201974c4584b2c9c3c549ef07be74569b85500cdf7a307d1efd8d8079de9c63a79830a59a8c85a1bb3aa4f86264c23db1d6e5135311824a276401d839198e426
|
data/README.md
CHANGED
@@ -1,28 +1,22 @@
|
|
1
1
|
# Localjob
|
2
2
|
|
3
|
-
Localjob is a simple, self-contained background queue built on top of [
|
4
|
-
message queues][
|
5
|
-
the same machine. It's the sqlite of
|
6
|
-
it works][blog].
|
3
|
+
Localjob is a simple, self-contained background queue built on top of [System V
|
4
|
+
message queues][sysv] (SysV Message Queue => SysV MQ for short). Workers and the
|
5
|
+
app pushing to the queue must reside on the same machine. It's the sqlite of
|
6
|
+
background queues. Here's a post about [how it works][blog].
|
7
7
|
|
8
8
|
Localjob is for early-development situations where you don't need a
|
9
9
|
full-featured background queue, but just want to get started with something
|
10
|
-
simple that does not rely on any external services.
|
11
|
-
|
12
|
-
|
13
|
-
your own code.
|
10
|
+
simple that does not rely on any external services. The advantage of the SysV
|
11
|
+
queues is that your Rails app or worker can restart at any time, without loosing
|
12
|
+
any events.
|
14
13
|
|
15
|
-
|
16
|
-
parameters for your application**, please consult [posix-mqueue][pmq-gem]'s
|
17
|
-
documentation.
|
18
|
-
|
19
|
-
Localjob works on Ruby >= 2.0.0. On Linux, it will use the POSIX message queue.
|
20
|
-
On OS X it will use SysV message queues.
|
14
|
+
Localjob works on Ruby >= 2.0.0 on Linux and OS X.
|
21
15
|
|
22
16
|
Add it to your Gemfile:
|
23
17
|
|
24
18
|
```ruby
|
25
|
-
gem 'localjob', "0.
|
19
|
+
gem 'localjob', "~> 0.2"
|
26
20
|
```
|
27
21
|
|
28
22
|
## Usage
|
@@ -48,10 +42,11 @@ queue = Localjob.new
|
|
48
42
|
queue << EmailJob.new(current_user.id, welcome_email)
|
49
43
|
```
|
50
44
|
|
51
|
-
A job is serialized with YAML and pushed onto a persistent
|
45
|
+
A job is serialized with YAML and pushed onto a persistent SysV Message Queue.
|
52
46
|
This means a worker does not have to listen on the queue to push things to it.
|
53
|
-
|
54
|
-
|
47
|
+
Pops off the message queue are atomic, so only one will receive the queue. This
|
48
|
+
means you can run multiple workers on the same machine if you wish. The workers
|
49
|
+
will deserialize the message to create an instance of your object, and call
|
55
50
|
`#perform` on the object.
|
56
51
|
|
57
52
|
### Rails initializer
|
@@ -61,7 +56,7 @@ constant referencing each of your queues. This allows easy access anywhere in
|
|
61
56
|
your app. In `config/initializers/localjob.rb`:
|
62
57
|
|
63
58
|
```ruby
|
64
|
-
BackgroundQueue = Localjob.new
|
59
|
+
BackgroundQueue = Localjob.new
|
65
60
|
```
|
66
61
|
|
67
62
|
Then in your app you can simply reference the constant to push to the queue:
|
@@ -83,19 +78,6 @@ Gracefully shut down workers by sending `SIGQUIT` to them. This will make sure
|
|
83
78
|
the worker completes its current job before shutting down. Jobs can be sent to
|
84
79
|
the queue meanwhile, and the worker will process them once it starts again.
|
85
80
|
|
86
|
-
### Queues
|
87
|
-
|
88
|
-
Localjobs supports multiple queues, and workers can be assigned to queues. By
|
89
|
-
default everything is on a single queue. To push to a named queue:
|
90
|
-
|
91
|
-
```ruby
|
92
|
-
email = Localjob.new("email")
|
93
|
-
email << EmailJob.new(current_user.id, welcome_email)
|
94
|
-
```
|
95
|
-
|
96
|
-
The worker spawn command `localjob work` takes a `--queues` argument which is a
|
97
|
-
comma seperated list of queues to listen on, e.g. `localjob work --queues email,webhooks`.
|
98
|
-
|
99
81
|
### Testing
|
100
82
|
|
101
83
|
Create your instance of the queue as normal in your setup:
|
@@ -103,7 +85,7 @@ Create your instance of the queue as normal in your setup:
|
|
103
85
|
```ruby
|
104
86
|
def setup
|
105
87
|
@queue = Localjob.new("test-queue")
|
106
|
-
@worker = Localjob::Worker.new("test-queue")
|
88
|
+
@worker = Localjob::Worker.new("test-queue")
|
107
89
|
end
|
108
90
|
```
|
109
91
|
|
@@ -132,6 +114,5 @@ def test_pop_and_send_to_worker
|
|
132
114
|
end
|
133
115
|
```
|
134
116
|
|
135
|
-
[
|
136
|
-
[pmq-gem]: https://github.com/Sirupsen/posix-mqueue
|
117
|
+
[sysv]: http://man7.org/linux/man-pages/man7/svipc.7.html
|
137
118
|
[blog]: http://sirupsen.com/unix-background-queue/
|
@@ -1,47 +1,34 @@
|
|
1
|
-
require '
|
1
|
+
require 'sysvmq'
|
2
2
|
|
3
3
|
class Localjob
|
4
|
-
class Channel
|
5
|
-
def shift
|
6
|
-
raise "SysV adapter does not support multiple queues" if @queues.size > 1
|
7
|
-
@queues.first.shift
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
4
|
class SysvAdapter
|
12
|
-
|
5
|
+
RECEIVE_ALL_TYPES = 0
|
13
6
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
unless @mq
|
20
|
-
File.open(@filename, "w") { }
|
21
|
-
key = ftok(@filename, 0)
|
22
|
-
|
23
|
-
@mq = MessageQueue.new(key, IPC_CREAT | 0600)
|
24
|
-
end
|
25
|
-
|
26
|
-
@mq
|
7
|
+
attr_reader :queue
|
8
|
+
|
9
|
+
def initialize(key, size: 8192, flags: SysVMQ::IPC_CREAT | 0660)
|
10
|
+
@key = key
|
11
|
+
@queue = SysVMQ.new(key, size, flags)
|
27
12
|
end
|
28
13
|
|
29
14
|
def receive
|
30
|
-
|
15
|
+
queue.receive(RECEIVE_ALL_TYPES)
|
31
16
|
end
|
32
17
|
|
33
18
|
def send(message)
|
34
|
-
|
19
|
+
queue.send(message, 1)
|
35
20
|
end
|
36
21
|
|
37
22
|
def size
|
38
|
-
|
23
|
+
queue.stats[:count]
|
24
|
+
end
|
25
|
+
|
26
|
+
def stats
|
27
|
+
queue.stats
|
39
28
|
end
|
40
29
|
|
41
30
|
def destroy
|
42
|
-
|
43
|
-
@mq.rm
|
44
|
-
@mq = nil
|
31
|
+
queue.destroy
|
45
32
|
end
|
46
33
|
end
|
47
34
|
end
|
data/lib/localjob/version.rb
CHANGED
data/lib/localjob/worker.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
class Localjob
|
2
2
|
class Worker
|
3
|
-
|
4
|
-
attr_reader :options
|
3
|
+
TERMINATION_MESSAGE = "__TERMINATE__"
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
attr_accessor :logger
|
6
|
+
attr_reader :options, :queue
|
7
|
+
|
8
|
+
def initialize(queue, logger: Logger.new(STDOUT), **options)
|
9
|
+
@queue, @logger = queue, logger
|
8
10
|
@options = options
|
9
11
|
@shutdown = false
|
10
12
|
end
|
@@ -18,35 +20,67 @@ class Localjob
|
|
18
20
|
Process.pid
|
19
21
|
end
|
20
22
|
|
21
|
-
def work
|
23
|
+
def work(thread: false)
|
22
24
|
logger.info "Worker #{pid} now listening!"
|
23
25
|
trap_signals
|
26
|
+
|
27
|
+
return work_thread if thread
|
28
|
+
|
24
29
|
create_pid_file(@options[:pid_file])
|
25
30
|
deamonize if @options[:deamon]
|
26
|
-
|
31
|
+
|
32
|
+
loop { break unless shift_and_process }
|
33
|
+
end
|
34
|
+
|
35
|
+
def kill
|
36
|
+
if @thread
|
37
|
+
Thread.kill(@thread)
|
38
|
+
@thread.join
|
39
|
+
else
|
40
|
+
shutdown
|
41
|
+
end
|
27
42
|
end
|
28
43
|
|
29
44
|
private
|
30
45
|
|
31
|
-
def
|
32
|
-
|
46
|
+
def work_thread
|
47
|
+
@thread = Thread.new do
|
48
|
+
begin
|
49
|
+
loop do
|
50
|
+
shift_and_process
|
51
|
+
end
|
52
|
+
# Respond to Thread.kill by sending termination message
|
53
|
+
ensure
|
54
|
+
shutdown
|
55
|
+
work
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
33
59
|
|
34
|
-
|
35
|
-
|
36
|
-
|
60
|
+
def shutdown!
|
61
|
+
logger.info "Worker #{pid} shutting down.."
|
62
|
+
File.rm(@options[:pid_file]) if @options[:pid_file]
|
63
|
+
return false if @thread
|
64
|
+
exit!
|
65
|
+
end
|
66
|
+
|
67
|
+
def shutdown
|
68
|
+
@queue << TERMINATION_MESSAGE
|
69
|
+
end
|
70
|
+
|
71
|
+
def shift_and_process
|
72
|
+
job = queue.shift
|
73
|
+
return shutdown! if job == TERMINATION_MESSAGE || !job
|
74
|
+
process(job)
|
75
|
+
return true # Explicit return of true, job#perform may return nil
|
76
|
+
rescue Object
|
37
77
|
logger.error "Worker #{pid} job failed: #{job}"
|
38
78
|
logger.error "#{$!}\n#{$@.join("\n")}"
|
39
79
|
end
|
40
80
|
|
41
81
|
def trap_signals
|
42
|
-
Signal.trap("QUIT") {
|
43
|
-
|
44
|
-
|
45
|
-
def wait
|
46
|
-
@waiting = true
|
47
|
-
job = yield
|
48
|
-
@waiting = false
|
49
|
-
job
|
82
|
+
Signal.trap("QUIT") { shutdown }
|
83
|
+
Signal.trap("INT") { shutdown }
|
50
84
|
end
|
51
85
|
|
52
86
|
def deamonize
|
@@ -56,10 +90,5 @@ class Localjob
|
|
56
90
|
def create_pid_file(path)
|
57
91
|
File.open(path, 'w') { |f| f << self.pid } if path
|
58
92
|
end
|
59
|
-
|
60
|
-
def graceful_shutdown
|
61
|
-
exit! if @waiting
|
62
|
-
@shutdown = true
|
63
|
-
end
|
64
93
|
end
|
65
94
|
end
|
data/lib/localjob.rb
CHANGED
@@ -3,15 +3,8 @@ require 'logger'
|
|
3
3
|
require 'forwardable'
|
4
4
|
|
5
5
|
require "localjob/version"
|
6
|
-
require 'localjob/channel'
|
7
6
|
require 'localjob/worker'
|
8
|
-
|
9
|
-
case RUBY_PLATFORM
|
10
|
-
when /linux/
|
11
|
-
require 'localjob/linux_adapter'
|
12
|
-
else
|
13
|
-
require 'localjob/sysv_adapter'
|
14
|
-
end
|
7
|
+
require 'localjob/sysv_adapter'
|
15
8
|
|
16
9
|
class Localjob
|
17
10
|
extend Forwardable
|
@@ -21,7 +14,8 @@ class Localjob
|
|
21
14
|
|
22
15
|
def_delegators :queue, :to_io, :destroy, :size
|
23
16
|
|
24
|
-
|
17
|
+
# LOCALJOB in 1337speak
|
18
|
+
def initialize(name = 0x10CA110B)
|
25
19
|
@name = name
|
26
20
|
end
|
27
21
|
|
@@ -30,14 +24,7 @@ class Localjob
|
|
30
24
|
end
|
31
25
|
|
32
26
|
def queue
|
33
|
-
|
34
|
-
|
35
|
-
case RUBY_PLATFORM
|
36
|
-
when /linux/
|
37
|
-
@queue = LinuxAdapter.new(@name)
|
38
|
-
else
|
39
|
-
@queue = SysvAdapter.new(@name)
|
40
|
-
end
|
27
|
+
@queue ||= SysvAdapter.new(@name)
|
41
28
|
end
|
42
29
|
|
43
30
|
def <<(object)
|
@@ -46,5 +33,8 @@ class Localjob
|
|
46
33
|
|
47
34
|
def shift
|
48
35
|
serializer.load queue.receive
|
36
|
+
# Bad serialization
|
37
|
+
rescue Object
|
38
|
+
nil
|
49
39
|
end
|
50
40
|
end
|
data/localjob.gemspec
CHANGED
@@ -17,12 +17,12 @@ Gem::Specification.new do |spec|
|
|
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
19
|
spec.require_paths = ["lib"]
|
20
|
-
spec.extensions = ["ext/mkrf_conf.rb"]
|
21
20
|
|
22
21
|
spec.add_dependency "thor", "0.18.1"
|
23
|
-
spec.add_dependency "
|
22
|
+
spec.add_dependency "sysvmq", "~> 0.1"
|
24
23
|
|
25
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
26
25
|
spec.add_development_dependency "rake"
|
27
26
|
spec.add_development_dependency "mocha"
|
27
|
+
spec.add_development_dependency "stackprof"
|
28
28
|
end
|
data/test/localjob_test.rb
CHANGED
@@ -21,18 +21,10 @@ class LocaljobTest < LocaljobTestCase
|
|
21
21
|
def test_handles_multiple_queues
|
22
22
|
@localjob << WalrusJob.new("move")
|
23
23
|
|
24
|
-
other = queue(
|
24
|
+
other = queue(0xDEADCAFE)
|
25
25
|
other << WalrusJob.new("dance")
|
26
26
|
|
27
27
|
assert_equal 1, @localjob.size
|
28
28
|
assert_equal 1, other.size
|
29
29
|
end
|
30
|
-
|
31
|
-
on_platform 'linux' do
|
32
|
-
def test_throws_error_if_message_is_too_large
|
33
|
-
assert_raises Errno::EMSGSIZE do
|
34
|
-
@localjob << AngryWalrusJob.new("f" * @localjob.queue.mqueue.msgsize)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
30
|
end
|
data/test/mock_adapter.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SysvAdapterTest < LocaljobTestCase
|
4
|
+
def setup
|
5
|
+
@localjob = queue
|
6
|
+
@localjob.queue = Localjob::SysvAdapter.new(0xDEADC0DE)
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
@localjob.destroy
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_send_and_receive
|
14
|
+
msg = "Hello World"
|
15
|
+
@localjob << msg
|
16
|
+
assert_equal msg, @localjob.shift
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_size
|
20
|
+
@localjob << "Hello World"
|
21
|
+
assert_equal 1, @localjob.size
|
22
|
+
end
|
23
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -8,13 +8,13 @@ require 'jobs'
|
|
8
8
|
class LocaljobTestCase < MiniTest::Unit::TestCase
|
9
9
|
protected
|
10
10
|
# This is a method to make sure the logger is set right.
|
11
|
-
def worker(
|
12
|
-
Localjob::Worker.new(
|
11
|
+
def worker(queue)
|
12
|
+
Localjob::Worker.new(queue, logger: logger)
|
13
13
|
end
|
14
14
|
|
15
15
|
# This is a method to make sure all queues are registred and destroyed after
|
16
16
|
# each teach run.
|
17
|
-
def queue(name =
|
17
|
+
def queue(name = 0x10CA110B)
|
18
18
|
@queues ||= []
|
19
19
|
queue = Localjob.new(name)
|
20
20
|
@queues << queue
|
@@ -22,7 +22,7 @@ class LocaljobTestCase < MiniTest::Unit::TestCase
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def teardown
|
25
|
-
|
25
|
+
clear_queues
|
26
26
|
end
|
27
27
|
|
28
28
|
def logger
|
@@ -32,19 +32,7 @@ class LocaljobTestCase < MiniTest::Unit::TestCase
|
|
32
32
|
@logger = Logger.new(output_file)
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
35
|
+
def clear_queues
|
36
36
|
@queues.each(&:destroy) if @queues
|
37
|
-
|
38
|
-
# This forces the GC to garbage collect, and thus close file descriptioners
|
39
|
-
# in POSIX::Mqueue. Otherwise we'll get flooded with warnings. This is to
|
40
|
-
# ensure a clean state everytime with a new message queue for each test.
|
41
|
-
# It's slower. But safe.
|
42
|
-
GC.start
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.on_platform(platform)
|
46
|
-
if RUBY_PLATFORM =~ /#{platform}/
|
47
|
-
yield
|
48
|
-
end
|
49
37
|
end
|
50
38
|
end
|
data/test/worker_test.rb
CHANGED
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
class WorkerTest < LocaljobTestCase
|
4
4
|
def setup
|
5
5
|
@localjob = queue
|
6
|
-
@worker = worker
|
6
|
+
@worker = worker(@localjob)
|
7
7
|
end
|
8
8
|
|
9
9
|
def test_pop_and_send_to_worker
|
@@ -33,58 +33,53 @@ class WorkerTest < LocaljobTestCase
|
|
33
33
|
@localjob << AngryWalrusJob.new(100)
|
34
34
|
@localjob << WalrusJob.new("be happy")
|
35
35
|
|
36
|
-
|
36
|
+
@worker.work(thread: true)
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
a.kill
|
38
|
+
sleep 0.1
|
39
|
+
@worker.kill
|
41
40
|
|
42
41
|
assert_equal 0, @localjob.size
|
43
42
|
end
|
44
43
|
|
45
44
|
def test_worker_doesnt_die_on_bad_serialization
|
46
|
-
@localjob
|
45
|
+
@localjob << "--- !ruby/object:Whatever {}\n"
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
a.kill
|
47
|
+
@worker.work(thread: true)
|
48
|
+
sleep 0.1
|
49
|
+
@worker.kill
|
52
50
|
end
|
53
51
|
|
54
|
-
|
55
|
-
|
56
|
-
# interrupt syscalls to give us signals.
|
57
|
-
def test_sigquit_terminates_the_worker
|
58
|
-
@localjob << WalrusJob.new("move")
|
52
|
+
def test_sigquit_terminates_the_worker
|
53
|
+
@localjob << WalrusJob.new("move")
|
59
54
|
|
60
|
-
|
55
|
+
assert_equal 1, @localjob.size
|
61
56
|
|
62
|
-
|
57
|
+
pid = fork { @worker.work }
|
58
|
+
sleep 0.1
|
63
59
|
|
64
|
-
|
65
|
-
sleep 0.1
|
60
|
+
Process.kill("QUIT", pid)
|
66
61
|
|
67
|
-
|
68
|
-
|
62
|
+
assert_equal 0, @localjob.size
|
63
|
+
end
|
69
64
|
|
70
|
-
|
71
|
-
|
65
|
+
def test_sigquit_terminates_the_worker
|
66
|
+
@localjob << WalrusJob.new("move")
|
72
67
|
|
73
|
-
|
74
|
-
|
68
|
+
pid = fork { @worker.work }
|
69
|
+
sleep 0.1
|
75
70
|
|
76
|
-
|
77
|
-
|
71
|
+
Process.kill("INT", pid)
|
72
|
+
end
|
78
73
|
|
79
|
-
|
74
|
+
def test_thread_worker
|
75
|
+
@localjob << WalrusJob.new("move")
|
80
76
|
|
81
|
-
|
77
|
+
assert_equal 1, @localjob.size
|
82
78
|
|
83
|
-
|
84
|
-
|
79
|
+
@worker.work(thread: true)
|
80
|
+
sleep 0.1
|
81
|
+
@worker.kill
|
85
82
|
|
86
|
-
|
87
|
-
assert_equal 0, other.size
|
88
|
-
end
|
83
|
+
assert_equal 0, @localjob.size
|
89
84
|
end
|
90
85
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: localjob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Eskildsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -25,59 +25,73 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.18.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: sysvmq
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
33
|
+
version: '0.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '0.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: mocha
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: stackprof
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
74
88
|
- !ruby/object:Gem::Version
|
75
89
|
version: '0'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- -
|
94
|
+
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
83
97
|
description: Simple, self-contained background queue built on top of POSIX message
|
@@ -86,21 +100,17 @@ email:
|
|
86
100
|
- sirup@sirupsen.com
|
87
101
|
executables:
|
88
102
|
- localjob
|
89
|
-
extensions:
|
90
|
-
- ext/mkrf_conf.rb
|
103
|
+
extensions: []
|
91
104
|
extra_rdoc_files: []
|
92
105
|
files:
|
93
|
-
- .gitignore
|
106
|
+
- ".gitignore"
|
94
107
|
- Gemfile
|
95
108
|
- LICENSE.txt
|
96
109
|
- README.md
|
97
110
|
- Rakefile
|
98
111
|
- bin/localjob
|
99
|
-
- ext/mkrf_conf.rb
|
100
112
|
- lib/localjob.rb
|
101
|
-
- lib/localjob/channel.rb
|
102
113
|
- lib/localjob/cli.rb
|
103
|
-
- lib/localjob/linux_adapter.rb
|
104
114
|
- lib/localjob/mock_adapter.rb
|
105
115
|
- lib/localjob/sysv_adapter.rb
|
106
116
|
- lib/localjob/version.rb
|
@@ -109,6 +119,7 @@ files:
|
|
109
119
|
- test/jobs.rb
|
110
120
|
- test/localjob_test.rb
|
111
121
|
- test/mock_adapter.rb
|
122
|
+
- test/sysv_adapter_test.rb
|
112
123
|
- test/test_helper.rb
|
113
124
|
- test/worker_test.rb
|
114
125
|
homepage: ''
|
@@ -121,17 +132,17 @@ require_paths:
|
|
121
132
|
- lib
|
122
133
|
required_ruby_version: !ruby/object:Gem::Requirement
|
123
134
|
requirements:
|
124
|
-
- -
|
135
|
+
- - ">="
|
125
136
|
- !ruby/object:Gem::Version
|
126
137
|
version: '0'
|
127
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
139
|
requirements:
|
129
|
-
- -
|
140
|
+
- - ">="
|
130
141
|
- !ruby/object:Gem::Version
|
131
142
|
version: '0'
|
132
143
|
requirements: []
|
133
144
|
rubyforge_project:
|
134
|
-
rubygems_version: 2.0
|
145
|
+
rubygems_version: 2.2.0
|
135
146
|
signing_key:
|
136
147
|
specification_version: 4
|
137
148
|
summary: Simple, self-contained background queue built on top of POSIX message queues.
|
@@ -140,5 +151,6 @@ test_files:
|
|
140
151
|
- test/jobs.rb
|
141
152
|
- test/localjob_test.rb
|
142
153
|
- test/mock_adapter.rb
|
154
|
+
- test/sysv_adapter_test.rb
|
143
155
|
- test/test_helper.rb
|
144
156
|
- test/worker_test.rb
|
data/ext/mkrf_conf.rb
DELETED
data/lib/localjob/channel.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
class Localjob
|
2
|
-
class Channel
|
3
|
-
attr_accessor :queues
|
4
|
-
|
5
|
-
def initialize(queues)
|
6
|
-
@queues = [queues].flatten.map { |q| queue_from_name(q) }
|
7
|
-
end
|
8
|
-
|
9
|
-
def <<(queue)
|
10
|
-
@queues << queue_from_name(queue)
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
def queue_from_name(queue)
|
15
|
-
queue.instance_of?(Localjob) ? queue : Localjob.new(queue)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'posix/mqueue'
|
2
|
-
|
3
|
-
class Localjob
|
4
|
-
class Channel
|
5
|
-
def shift
|
6
|
-
(queue,), = IO.select(@queues)
|
7
|
-
queue.shift
|
8
|
-
rescue POSIX::Mqueue::QueueEmpty
|
9
|
-
retry
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class LinuxAdapter
|
14
|
-
attr_reader :mqueue
|
15
|
-
|
16
|
-
def initialize(name)
|
17
|
-
@mqueue = POSIX::Mqueue.new(fix_queue_name(name))
|
18
|
-
end
|
19
|
-
|
20
|
-
def receive
|
21
|
-
@mqueue.timedreceive
|
22
|
-
end
|
23
|
-
|
24
|
-
def send(message)
|
25
|
-
@mqueue.timedsend message
|
26
|
-
end
|
27
|
-
|
28
|
-
def size
|
29
|
-
@mqueue.size
|
30
|
-
end
|
31
|
-
|
32
|
-
def destroy
|
33
|
-
@mqueue.unlink
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_io
|
37
|
-
@mqueue.to_io
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
def fix_queue_name(name)
|
42
|
-
name.start_with?('/') ? name : "/#{name}"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|