localjob 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: becc6c53c0de0692e654c0e4fd8b220b13baa424
4
- data.tar.gz: 770a92796d0fedf97c3d66728e039b3d966e7f92
3
+ metadata.gz: 6c33dc84596d653899831a3697428d950028e0c5
4
+ data.tar.gz: 8547e6ca4022b618956578e8dc3f11fe65ae8b00
5
5
  SHA512:
6
- metadata.gz: f56f0b1ae32cda8650cd0e6375278ad34bf16c00db257a180d1070c980c7eee422f7e604afcbbe013c7da7c0ae403d2f0a7c795987fd52330f101fd19f3a985e
7
- data.tar.gz: 3ecf92a571bd824625ea348b5f0ccdf8e4f5b7e3ba2fc3ab468a1915c90a768f5a250803d71a8a1caf41387c21d237320f605c250e6edcf4bdbcc035d4b1c90f
6
+ metadata.gz: 22eab445b06c1011c53a244a2677feec403a4f501e0dc35ca663b405d4d754f3f891914420fb811a5a840076f1fbd6af71f7afc31d5f1e9c76a297730fbf281c
7
+ data.tar.gz: d7ede95238c734c9ab043b2861152203197fb7606a86ee6b81083ce304c9f479cbaf50842515301518f6566733b7978a1b77dff828827df476e9dd5505191199
data/README.md CHANGED
@@ -12,18 +12,18 @@ project is to be able to migrate to another background queue system by switching
12
12
  adapter: `Localjob.adapter = Resque` to switch to Resque, without changes to
13
13
  your own code.
14
14
 
15
- The POSIX message queue is persistent till reboot. You will need to tune system
16
- parameters for your application, please consult [posix-mqueue][pmq-gem]'s
15
+ The POSIX message queue is persistent till reboot. You **will need to tune system
16
+ parameters for your application**, please consult [posix-mqueue][pmq-gem]'s
17
17
  documentation.
18
18
 
19
- Localjob works on Ruby >= 2.0.0 and Linux.
19
+ Localjob works on Ruby >= 2.0.0. On Linux, it will use the POSIX message queue.
20
+ On OS X (and Windows, not tested) it will use a mock class instead of the
21
+ message queue, to aid you in testing and running Localjob in development.
20
22
 
21
- WIP not everything works as advertised, but try it out and report anything that
22
- doesn't work! It's not released as a gem yet, so add the following to your
23
- Gemfile to use it:
23
+ Add it to your Gemfile:
24
24
 
25
25
  ```ruby
26
- gem 'localjob', git: "git@github.com:Sirupsen/localjob.git"
26
+ gem 'localjob'
27
27
  ```
28
28
 
29
29
  ## Usage
@@ -49,8 +49,88 @@ queue = Localjob.new
49
49
  queue << EmailJob.new(current_user.id, welcome_email)
50
50
  ```
51
51
 
52
- Then spawn a worker with `localjob work`. It takes a few arguments, like `-d` to
53
- deamonize itself. `localjob help work` to list all options.
52
+ A job is serialized with YAML and pushed onto a persistent POSIX message queue.
53
+ This means a worker does not have to listen on the queue to push things to it.
54
+ Workers will pop off the message queue, but only one will receive the job.
55
+ Deserialize the message to create an instance of your object, and call
56
+ `#perform` on the object.
57
+
58
+ ### Rails initializer
59
+
60
+ For easy access to your queues in Rails, you can add an initializer to set up a
61
+ constant referencing each of your queues. This allows easy access anywhere in
62
+ your app. In `config/initializers/localjob.rb`:
63
+
64
+ ```ruby
65
+ BackgroundQueue = Localjob.new("main-queue")
66
+ ```
67
+
68
+ Then in your app you can simply reference the constant to push to the queue:
69
+
70
+ ```ruby
71
+ BackgroundQueue << EmailJob.new(current_user.id, welcome_email)
72
+ ```
73
+
74
+ ### Managing workers
75
+
76
+ Spawning workers can be done with `localjob`. Run `localjob work` to spawn a
77
+ single worker. It takes a few arguments. The most important being `--require`
78
+ which takes a path the worker will require before processing jobs. For Rails,
79
+ you can run `localjob work` without any arguments. `localjob(2)` has a few other
80
+ commands such as `list` to list all queues and `size` to list the size of all
81
+ queues. `localjob help` to list all commands.
82
+
83
+ Gracefully shut down workers by sending `SIGQUIT` to them. This will make sure
84
+ the worker completes its current job before shutting down. Jobs can be sent to
85
+ the queue meanwhile, and the worker will process them once it starts again.
86
+
87
+ ### Queues
88
+
89
+ Localjobs supports multiple queues, and workers can be assigned to queues. By
90
+ default everything is on a single queue. To push to a named queue:
91
+
92
+ ```ruby
93
+ email = Localjob.new("email")
94
+ email << EmailJob.new(current_user.id, welcome_email)
95
+ ```
96
+
97
+ The worker spawn command `localjob work` takes a `--queues` argument which is a
98
+ comma seperated list of queues to listen on, e.g. `localjob work --queues email,webhooks`.
99
+
100
+ ### Testing
101
+
102
+ Create your instance of the queue as normal in your setup:
103
+
104
+ ```ruby
105
+ def setup
106
+ @queue = LocalJob.new("test-queue")
107
+ end
108
+ ```
109
+
110
+ In your `teardown` you'll want to destroy your queue:
111
+
112
+ ```ruby
113
+ def teardown
114
+ @queue.destroy
115
+ end
116
+ ```
117
+
118
+ You can get the size of your queue by calling `@queue.size`. You pop off the
119
+ queue with `@queue.shift`. Other than that, just use the normal API. You can
120
+ also read the tests for Localjob to get an idea of how to test. Sample test:
121
+
122
+ ```ruby
123
+ def test_pop_and_send_to_worker
124
+ WalrusJob.any_instance.expects(:perform)
125
+
126
+ @localjob << WalrusJob.new("move")
127
+
128
+ job = @localjob.shift
129
+ @worker.process(job)
130
+
131
+ assert_equal 0, @localjob.size
132
+ end
133
+ ```
54
134
 
55
135
  [pmq]: http://linux.die.net/man/7/mq_overview
56
136
  [pmq-gem]: https://github.com/Sirupsen/posix-mqueue
data/ext/mkrf_conf.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'rubygems/command.rb'
3
+ require 'rubygems/dependency_installer.rb'
4
+ begin
5
+ Gem::Command.build_args = ARGV
6
+ rescue NoMethodError
7
+ end
8
+
9
+ inst = Gem::DependencyInstaller.new
10
+
11
+ begin
12
+ if RUBY_PLATFORM =~ /linux/
13
+ inst.install "posix-mqueue", "0.0.7"
14
+ end
15
+ rescue
16
+ exit(1)
17
+ end
@@ -11,10 +11,12 @@ class Localjob
11
11
  end
12
12
 
13
13
  def shift
14
- (queue,), = IO.select(@queues)
15
- queue.shift
16
- rescue POSIX::Mqueue::QueueEmpty
17
- retry
14
+ begin
15
+ (queue,), = IO.select(@queues)
16
+ queue.shift
17
+ rescue POSIX::Mqueue::QueueEmpty
18
+ retry
19
+ end
18
20
  end
19
21
 
20
22
  private
@@ -0,0 +1,34 @@
1
+ class Localjob
2
+ class LinuxAdapter
3
+ attr_reader :mqueue
4
+
5
+ def initialize(name)
6
+ @mqueue = POSIX::Mqueue.new(fix_queue_name(name))
7
+ end
8
+
9
+ def receive
10
+ @mqueue.timedreceive
11
+ end
12
+
13
+ def send(message)
14
+ @mqueue.timedsend message
15
+ end
16
+
17
+ def size
18
+ @mqueue.size
19
+ end
20
+
21
+ def destroy
22
+ @mqueue.unlink
23
+ end
24
+
25
+ def to_io
26
+ @mqueue.to_io
27
+ end
28
+
29
+ private
30
+ def fix_queue_name(name)
31
+ name.start_with?('/') ? name : "/#{name}"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ class Localjob
2
+ class Channel
3
+ def shift
4
+ queue = @queues.find { |q| q.size > 0 }
5
+ return queue.shift
6
+ end
7
+ end
8
+
9
+ class MockAdapter
10
+ def initialize(name = 'default')
11
+ @@queues ||= {}
12
+ @name = name
13
+ @@queues[@name] ||= []
14
+ end
15
+
16
+ def receive
17
+ @@queues[@name].shift
18
+ end
19
+
20
+ def send(message)
21
+ @@queues[@name] << message
22
+ end
23
+
24
+ def size
25
+ @@queues[@name].size
26
+ end
27
+
28
+ def destroy
29
+ @@queues[@name] = nil
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,3 @@
1
1
  class Localjob
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/localjob.rb CHANGED
@@ -1,16 +1,26 @@
1
- require 'posix/mqueue'
1
+ begin
2
+ require 'posix/mqueue'
3
+ rescue LoadError
4
+ end
5
+
2
6
  require 'yaml'
3
7
  require 'logger'
8
+ require 'forwardable'
4
9
 
5
10
  require "localjob/version"
6
11
  require 'localjob/channel'
7
12
  require 'localjob/worker'
8
13
 
9
14
  class Localjob
10
- attr_reader :queue_name
15
+ extend Forwardable
16
+
17
+ attr_reader :name
18
+ attr_accessor :queue
19
+
20
+ def_delegators :queue, :to_io, :destroy, :size
11
21
 
12
- def initialize(queue = "localjob")
13
- @queue_name = fix_queue_name(queue)
22
+ def initialize(name = "localjob")
23
+ @name = name
14
24
  end
15
25
 
16
26
  def serializer
@@ -18,31 +28,23 @@ class Localjob
18
28
  end
19
29
 
20
30
  def queue
21
- @queue ||= POSIX::Mqueue.new(@queue_name)
22
- end
31
+ return @queue if @queue
23
32
 
24
- def <<(object)
25
- queue.timedsend serializer.dump(object)
33
+ case RUBY_PLATFORM
34
+ when /linux/
35
+ require 'localjob/linux_adapter'
36
+ @queue = LinuxAdapter.new(@name)
37
+ else
38
+ require 'localjob/mock_adapter'
39
+ @queue = MockAdapter.new(@name)
40
+ end
26
41
  end
27
42
 
28
- def size
29
- queue.size
43
+ def <<(object)
44
+ queue.send serializer.dump(object)
30
45
  end
31
46
 
32
47
  def shift
33
- serializer.load queue.timedreceive
34
- end
35
-
36
- def destroy
37
- queue.unlink
38
- end
39
-
40
- def to_io
41
- queue.to_io
42
- end
43
-
44
- private
45
- def fix_queue_name(queue)
46
- queue.start_with?('/') ? queue : "/#{queue}"
48
+ serializer.load queue.receive
47
49
  end
48
50
  end
data/localjob.gemspec CHANGED
@@ -17,8 +17,8 @@ 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"]
20
21
 
21
- spec.add_dependency "posix-mqueue", "0.0.9"
22
22
  spec.add_dependency "thor", "0.18.1"
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
@@ -18,12 +18,6 @@ class LocaljobTest < LocaljobTestCase
18
18
  assert_equal "move", job.action
19
19
  end
20
20
 
21
- def test_throws_error_if_message_is_too_large
22
- assert_raises Errno::EMSGSIZE do
23
- @localjob << AngryWalrusJob.new("f" * @localjob.queue.msgsize)
24
- end
25
- end
26
-
27
21
  def test_handles_multiple_queues
28
22
  @localjob << WalrusJob.new("move")
29
23
 
@@ -33,4 +27,12 @@ class LocaljobTest < LocaljobTestCase
33
27
  assert_equal 1, @localjob.size
34
28
  assert_equal 1, other.size
35
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
36
38
  end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ class MockAdapterTest < LocaljobTestCase
4
+ def setup
5
+ @localjob = queue
6
+ @localjob.queue = Localjob::MockAdapter.new("localjob")
7
+ end
8
+
9
+ def test_push_to_queue
10
+ @localjob << "hello world"
11
+ assert_equal 1, @localjob.size
12
+ end
13
+
14
+ def test_push_and_pop_from_queue
15
+ @localjob << "hello world"
16
+ assert_equal "hello world", @localjob.shift
17
+ end
18
+
19
+ def test_destroy_queue
20
+ @localjob << "hello world"
21
+ end
22
+ end
data/test/test_helper.rb CHANGED
@@ -41,4 +41,10 @@ class LocaljobTestCase < MiniTest::Unit::TestCase
41
41
  # It's slower. But safe.
42
42
  GC.start
43
43
  end
44
+
45
+ def self.on_platform(platform)
46
+ if RUBY_PLATFORM =~ /#{platform}/
47
+ yield
48
+ end
49
+ end
44
50
  end
data/test/worker_test.rb CHANGED
@@ -18,38 +18,26 @@ class WorkerTest < LocaljobTestCase
18
18
  def test_working_off_queue_in_child
19
19
  @localjob << WalrusJob.new("move")
20
20
 
21
- fork do
21
+ a = Thread.start {
22
22
  job = @localjob.shift
23
23
  @worker.process(job)
24
- end
25
-
26
- Process.wait
27
- assert_equal 0, @localjob.size
28
- end
29
-
30
- def test_sigquit_terminates_the_worker
31
- @localjob << WalrusJob.new("move")
32
-
33
- assert_equal 1, @localjob.size
34
-
35
- pid = fork { @worker.work }
24
+ }
36
25
 
37
- Process.kill("QUIT", pid)
38
- Process.wait
26
+ a.join
39
27
 
40
28
  assert_equal 0, @localjob.size
41
29
  end
42
30
 
31
+
43
32
  def test_doesnt_stop_on_error
44
33
  @localjob << AngryWalrusJob.new(100)
45
34
  @localjob << WalrusJob.new("be happy")
46
35
 
47
- pid = fork { @worker.work }
36
+ a = Thread.start { @worker.work }
48
37
 
49
38
  # Hack to account for race condition, 0.01s should be plenty
50
39
  sleep 0.01
51
- Process.kill("QUIT", pid)
52
- Process.wait
40
+ a.kill
53
41
 
54
42
  assert_equal 0, @localjob.size
55
43
  end
@@ -62,24 +50,36 @@ class WorkerTest < LocaljobTestCase
62
50
 
63
51
  @worker.channel << 'other-queue'
64
52
 
65
- pid = fork { @worker.work }
53
+ a = Thread.start { @worker.work }
66
54
 
67
- # Hack to account for race condition, 0.01s should be plenty
68
55
  sleep 0.01
69
- Process.kill("QUIT", pid)
70
- Process.wait
56
+ a.kill
71
57
 
72
58
  assert_equal 0, @localjob.size
73
59
  assert_equal 0, other.size
74
60
  end
75
61
 
76
62
  def test_worker_doesnt_die_on_bad_serialization
77
- @localjob.queue.timedsend "--- !ruby/object:Whatever {}\n"
63
+ @localjob.queue.send "--- !ruby/object:Whatever {}\n"
78
64
 
79
- pid = fork { @worker.work }
65
+ a = Thread.start { @worker.work }
80
66
 
81
67
  sleep 0.01
82
- Process.kill("QUIT", pid)
83
- Process.wait
68
+ a.kill
69
+ end
70
+
71
+ on_platform 'linux' do
72
+ def test_sigquit_terminates_the_worker
73
+ @localjob << WalrusJob.new("move")
74
+
75
+ assert_equal 1, @localjob.size
76
+
77
+ pid = fork { @worker.work }
78
+
79
+ Process.kill("QUIT", pid)
80
+ Process.wait
81
+
82
+ assert_equal 0, @localjob.size
83
+ end
84
84
  end
85
85
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: localjob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Eskildsen
@@ -10,20 +10,6 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2013-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: posix-mqueue
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - '='
18
- - !ruby/object:Gem::Version
19
- version: 0.0.9
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - '='
25
- - !ruby/object:Gem::Version
26
- version: 0.0.9
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: thor
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -86,7 +72,8 @@ email:
86
72
  - sirup@sirupsen.com
87
73
  executables:
88
74
  - localjob
89
- extensions: []
75
+ extensions:
76
+ - ext/mkrf_conf.rb
90
77
  extra_rdoc_files: []
91
78
  files:
92
79
  - .gitignore
@@ -95,14 +82,18 @@ files:
95
82
  - README.md
96
83
  - Rakefile
97
84
  - bin/localjob
85
+ - ext/mkrf_conf.rb
98
86
  - lib/localjob.rb
99
87
  - lib/localjob/channel.rb
100
88
  - lib/localjob/cli.rb
89
+ - lib/localjob/linux_adapter.rb
90
+ - lib/localjob/mock_adapter.rb
101
91
  - lib/localjob/version.rb
102
92
  - lib/localjob/worker.rb
103
93
  - localjob.gemspec
104
94
  - test/jobs.rb
105
95
  - test/localjob_test.rb
96
+ - test/mock_adapter.rb
106
97
  - test/test_helper.rb
107
98
  - test/worker_test.rb
108
99
  homepage: ''
@@ -133,5 +124,6 @@ summary: Simple, self-contained background queue built on top of POSIX message q
133
124
  test_files:
134
125
  - test/jobs.rb
135
126
  - test/localjob_test.rb
127
+ - test/mock_adapter.rb
136
128
  - test/test_helper.rb
137
129
  - test/worker_test.rb