employer 0.2 → 0.3
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/.travis.yml +5 -0
- data/README.md +3 -3
- data/employer.gemspec +2 -1
- data/lib/employer.rb +1 -0
- data/lib/employer/boss.rb +7 -5
- data/lib/employer/cli.rb +3 -1
- data/lib/employer/employees/abstract_employee.rb +7 -1
- data/lib/employer/logger.rb +47 -0
- data/lib/employer/pipeline.rb +10 -0
- data/lib/employer/version.rb +1 -1
- data/lib/employer/workshop.rb +26 -27
- data/spec/employer/boss_spec.rb +36 -16
- data/spec/employer/logger_spec.rb +95 -0
- data/spec/employer/pipeline_spec.rb +11 -1
- data/spec/employer/workshop_spec.rb +105 -78
- data/spec/support/shared_examples/employee.rb +9 -1
- metadata +29 -3
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Employer
|
1
|
+
# Employer [](https://travis-ci.org/mkremer/employer)
|
2
2
|
|
3
3
|
There comes a time in the life of an application that async job processing
|
4
4
|
becomes a requirement. If you want something flexible that you can easily adapt
|
@@ -140,13 +140,13 @@ forking_employees 4
|
|
140
140
|
The comments in the file pretty much explain how you should edit it.
|
141
141
|
|
142
142
|
When setup properly you can start processing jobs by running `employer` (or
|
143
|
-
`employer -c /path/to/
|
143
|
+
`employer -c /path/to/employer_config.rb`, likely prepended with `bundle exec`)
|
144
144
|
|
145
145
|
In your application code you can obtain a pipeline to enqueue jobs with like so:
|
146
146
|
|
147
147
|
```ruby
|
148
148
|
# Obtain the pipeline
|
149
|
-
pipeline = Employer::Workshop.enqueue("/path/to/
|
149
|
+
pipeline = Employer::Workshop.enqueue("/path/to/employer_config.rb")
|
150
150
|
|
151
151
|
# Enqueue a job
|
152
152
|
job = NamePutsJob.new
|
data/employer.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = Employer::VERSION
|
9
9
|
gem.authors = ["Mark Kremer"]
|
10
10
|
gem.email = ["mark@without-brains.net"]
|
11
|
-
gem.summary = %q{Job processing made easy}
|
11
|
+
gem.summary = %q{Job processing with pluggable backends made easy}
|
12
12
|
gem.homepage = "https://github.com/mkremer/employer"
|
13
13
|
gem.license = "MIT"
|
14
14
|
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.add_runtime_dependency "thor", "~> 0.17"
|
21
21
|
|
22
|
+
gem.add_development_dependency "rake"
|
22
23
|
gem.add_development_dependency "rspec"
|
23
24
|
gem.add_development_dependency "pry"
|
24
25
|
end
|
data/lib/employer.rb
CHANGED
data/lib/employer/boss.rb
CHANGED
@@ -2,16 +2,17 @@ require_relative "errors"
|
|
2
2
|
|
3
3
|
module Employer
|
4
4
|
class Boss
|
5
|
-
attr_reader :pipeline, :employees, :keep_going, :sleep_time
|
5
|
+
attr_reader :pipeline, :logger, :employees, :keep_going, :sleep_time
|
6
6
|
|
7
|
-
def initialize
|
8
|
-
@
|
7
|
+
def initialize(logger)
|
8
|
+
@logger = logger
|
9
|
+
@pipeline = Employer::Pipeline.new(logger)
|
9
10
|
@employees = []
|
10
11
|
@sleep_time_index = 0
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
|
14
|
+
def pipeline_backend=(backend)
|
15
|
+
pipeline.backend = backend
|
15
16
|
end
|
16
17
|
|
17
18
|
def allocate_employee(employee)
|
@@ -92,6 +93,7 @@ module Employer
|
|
92
93
|
|
93
94
|
def delegate_job(job)
|
94
95
|
raise Employer::Errors::NoEmployeeFree unless employee = free_employee
|
96
|
+
logger.info("Delegating job #{job.id} to employee #{employee.object_id}")
|
95
97
|
employee.work(job)
|
96
98
|
end
|
97
99
|
|
data/lib/employer/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "thor"
|
2
2
|
require "fileutils"
|
3
|
+
require "logger"
|
3
4
|
|
4
5
|
module Employer
|
5
6
|
class CLI < Thor
|
@@ -14,7 +15,8 @@ module Employer
|
|
14
15
|
end
|
15
16
|
|
16
17
|
int_count = 0
|
17
|
-
workshop = Employer::Workshop.
|
18
|
+
workshop = Employer::Workshop.new(File.read(options[:config]))
|
19
|
+
workshop.log_to(::Logger.new(STDOUT))
|
18
20
|
|
19
21
|
Signal.trap("INT") do
|
20
22
|
int_count += 1
|
@@ -3,7 +3,11 @@ require_relative "../errors"
|
|
3
3
|
module Employer
|
4
4
|
module Employees
|
5
5
|
class AbstractEmployee
|
6
|
-
attr_reader :job
|
6
|
+
attr_reader :job, :logger
|
7
|
+
|
8
|
+
def initialize(logger)
|
9
|
+
@logger = logger
|
10
|
+
end
|
7
11
|
|
8
12
|
def work(job)
|
9
13
|
raise Employer::Errors::EmployeeBusy unless free?
|
@@ -11,7 +15,9 @@ module Employer
|
|
11
15
|
end
|
12
16
|
|
13
17
|
def perform_job
|
18
|
+
logger.debug("Employee #{self.object_id} is now performing job #{job.id}")
|
14
19
|
job.perform
|
20
|
+
logger.debug("Employee #{self.object_id} has now completed #{job.id}")
|
15
21
|
end
|
16
22
|
|
17
23
|
def wait_for_completion
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Employer
|
2
|
+
class Logger
|
3
|
+
attr_reader :loggers
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@loggers = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def append_to(logger)
|
10
|
+
loggers << logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def debug(message = nil, &block)
|
14
|
+
log(:debug, message, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def error(message = nil, &block)
|
18
|
+
log(:error, message, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def warn(message = nil, &block)
|
22
|
+
log(:warn, message, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def info(message = nil, &block)
|
26
|
+
log(:info, message, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def fatal(message = nil, &block)
|
30
|
+
log(:fatal, message, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def log(level, message = nil, &block)
|
36
|
+
loggers.each do |logger|
|
37
|
+
next unless logger.respond_to?(level)
|
38
|
+
|
39
|
+
if message
|
40
|
+
logger.public_send(level, message)
|
41
|
+
elsif block
|
42
|
+
logger.public_send(level, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/employer/pipeline.rb
CHANGED
@@ -2,6 +2,12 @@ require_relative "errors"
|
|
2
2
|
|
3
3
|
module Employer
|
4
4
|
class Pipeline
|
5
|
+
attr_reader :logger
|
6
|
+
|
7
|
+
def initialize(logger)
|
8
|
+
@logger = logger
|
9
|
+
end
|
10
|
+
|
5
11
|
def backend=(backend)
|
6
12
|
@backend = backend
|
7
13
|
end
|
@@ -26,21 +32,25 @@ module Employer
|
|
26
32
|
|
27
33
|
def clear
|
28
34
|
raise Employer::Errors::PipelineBackendRequired if backend.nil?
|
35
|
+
logger.info("Clearing pipeline of all jobs!")
|
29
36
|
backend.clear
|
30
37
|
end
|
31
38
|
|
32
39
|
def complete(job)
|
33
40
|
raise Employer::Errors::PipelineBackendRequired if backend.nil?
|
41
|
+
logger.info("Marking job #{job.id} as complete")
|
34
42
|
backend.complete(job)
|
35
43
|
end
|
36
44
|
|
37
45
|
def reset(job)
|
38
46
|
raise Employer::Errors::PipelineBackendRequired if backend.nil?
|
47
|
+
logger.info("Resetting job #{job.id}")
|
39
48
|
backend.reset(job)
|
40
49
|
end
|
41
50
|
|
42
51
|
def fail(job)
|
43
52
|
raise Employer::Errors::PipelineBackendRequired if backend.nil?
|
53
|
+
logger.info("Marking job #{job.id} as failed")
|
44
54
|
backend.fail(job)
|
45
55
|
end
|
46
56
|
|
data/lib/employer/version.rb
CHANGED
data/lib/employer/workshop.rb
CHANGED
@@ -2,16 +2,29 @@ require_relative "errors"
|
|
2
2
|
|
3
3
|
module Employer
|
4
4
|
class Workshop
|
5
|
-
|
6
|
-
boss = Employer::Boss.new
|
7
|
-
pipeline = Employer::Pipeline.new
|
8
|
-
boss.pipeline = pipeline
|
9
|
-
workshop = new(boss, config_code, skip_employees)
|
10
|
-
end
|
5
|
+
attr_reader :logger
|
11
6
|
|
12
7
|
def self.pipeline(filename)
|
13
|
-
|
14
|
-
|
8
|
+
new(File.read(filename), true).pipeline
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(config_code, skip_employees = false)
|
12
|
+
@logger = Employer::Logger.new
|
13
|
+
@boss = Employer::Boss.new(logger)
|
14
|
+
@forking_employees = 0
|
15
|
+
@threading_employees = 0
|
16
|
+
|
17
|
+
instance_eval(config_code)
|
18
|
+
|
19
|
+
unless skip_employees
|
20
|
+
@forking_employees.times do
|
21
|
+
@boss.allocate_employee(Employer::Employees::ForkingEmployee.new(logger))
|
22
|
+
end
|
23
|
+
|
24
|
+
@threading_employees.times do
|
25
|
+
@boss.allocate_employee(Employer::Employees::ThreadingEmployee.new(logger))
|
26
|
+
end
|
27
|
+
end
|
15
28
|
end
|
16
29
|
|
17
30
|
def run
|
@@ -31,6 +44,10 @@ module Employer
|
|
31
44
|
@boss.pipeline
|
32
45
|
end
|
33
46
|
|
47
|
+
def log_to(log_to_logger)
|
48
|
+
logger.append_to(log_to_logger)
|
49
|
+
end
|
50
|
+
|
34
51
|
private
|
35
52
|
|
36
53
|
def forking_employees(number)
|
@@ -42,25 +59,7 @@ module Employer
|
|
42
59
|
end
|
43
60
|
|
44
61
|
def pipeline_backend(backend)
|
45
|
-
@boss.
|
46
|
-
end
|
47
|
-
|
48
|
-
def initialize(boss, config_code, skip_employees)
|
49
|
-
@boss = boss
|
50
|
-
@forking_employees = 0
|
51
|
-
@threading_employees = 0
|
52
|
-
|
53
|
-
instance_eval(config_code)
|
54
|
-
|
55
|
-
unless skip_employees
|
56
|
-
@forking_employees.times do
|
57
|
-
@boss.allocate_employee(Employer::Employees::ForkingEmployee.new)
|
58
|
-
end
|
59
|
-
|
60
|
-
@threading_employees.times do
|
61
|
-
@boss.allocate_employee(Employer::Employees::ThreadingEmployee.new)
|
62
|
-
end
|
63
|
-
end
|
62
|
+
@boss.pipeline_backend = backend
|
64
63
|
end
|
65
64
|
end
|
66
65
|
end
|
data/spec/employer/boss_spec.rb
CHANGED
@@ -1,23 +1,49 @@
|
|
1
1
|
require "employer/boss"
|
2
2
|
|
3
3
|
describe Employer::Boss do
|
4
|
+
before(:each) do
|
5
|
+
stub_const("Employer::Pipeline", Class.new)
|
6
|
+
Employer::Pipeline.stub(:new).and_return(pipeline)
|
7
|
+
end
|
8
|
+
|
4
9
|
let(:pipeline) { double("Pipeline") }
|
5
10
|
let(:employee) { double("Employee") }
|
6
11
|
let(:free_employee) { double("Free employee", free?: true) }
|
7
12
|
let(:busy_employee) { double("Busy employee", free?: false) }
|
8
|
-
let(:
|
13
|
+
let(:logger) { double("Logger").as_null_object }
|
14
|
+
let(:boss) { Employer::Boss.new(logger) }
|
9
15
|
|
10
|
-
|
11
|
-
|
12
|
-
|
16
|
+
describe "#initialize" do
|
17
|
+
let(:logger) { double("Logger") }
|
18
|
+
|
19
|
+
it "sets the logger" do
|
20
|
+
boss = Employer::Boss.new(logger)
|
21
|
+
boss.logger.should eq(logger)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "sets a pipeline with the logger" do
|
25
|
+
Employer::Pipeline.should_receive(:new).with(logger).and_return(pipeline)
|
26
|
+
boss = Employer::Boss.new(logger)
|
27
|
+
boss.pipeline.should eq(pipeline)
|
28
|
+
end
|
13
29
|
end
|
14
30
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
31
|
+
describe "#pipeline_backend=" do
|
32
|
+
it "sets the pipeline backend" do
|
33
|
+
backend = double("Backend")
|
34
|
+
boss.pipeline.should_receive(:backend=).with(backend)
|
35
|
+
boss.pipeline_backend = backend
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#allocate_employee" do
|
40
|
+
it "can be given employees" do
|
41
|
+
john = double
|
42
|
+
jane = double
|
43
|
+
boss.allocate_employee(john)
|
44
|
+
boss.allocate_employee(jane)
|
45
|
+
boss.employees.should eq([john, jane])
|
46
|
+
end
|
21
47
|
end
|
22
48
|
|
23
49
|
describe "#manage" do
|
@@ -47,7 +73,6 @@ describe Employer::Boss do
|
|
47
73
|
|
48
74
|
before(:each) do
|
49
75
|
boss.stub(:get_work).and_return(job1, job2, nil, nil)
|
50
|
-
boss.pipeline = pipeline
|
51
76
|
end
|
52
77
|
|
53
78
|
it "puts free employees to work while work is available" do
|
@@ -85,7 +110,6 @@ describe Employer::Boss do
|
|
85
110
|
describe "#get_work" do
|
86
111
|
before(:each) do
|
87
112
|
pipeline.stub(:dequeue).and_return(nil)
|
88
|
-
boss.pipeline = pipeline
|
89
113
|
end
|
90
114
|
|
91
115
|
it "increases sleep time each time it gets no job" do
|
@@ -116,10 +140,6 @@ describe Employer::Boss do
|
|
116
140
|
end
|
117
141
|
|
118
142
|
describe "#update_job_status" do
|
119
|
-
before(:each) do
|
120
|
-
boss.pipeline = pipeline
|
121
|
-
end
|
122
|
-
|
123
143
|
let(:job) { double("Job") }
|
124
144
|
let(:employee) { employee = double("Employee", job: job) }
|
125
145
|
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "employer/logger"
|
2
|
+
|
3
|
+
describe Employer::Logger do
|
4
|
+
let(:logger) { Employer::Logger.new }
|
5
|
+
let(:stdout_logger) { double("STDOUT Logger") }
|
6
|
+
let(:file_logger) { double("File Logger") }
|
7
|
+
let(:message) { "log me, please" }
|
8
|
+
let(:block) { lambda { "log me please" } }
|
9
|
+
|
10
|
+
describe "#append_to" do
|
11
|
+
it "accepts other loggers to write to" do
|
12
|
+
logger.append_to(stdout_logger)
|
13
|
+
logger.append_to(file_logger)
|
14
|
+
logger.loggers.should include(stdout_logger)
|
15
|
+
logger.loggers.should include(file_logger)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with loggers assigned" do
|
20
|
+
before(:each) do
|
21
|
+
logger.append_to(stdout_logger)
|
22
|
+
logger.append_to(file_logger)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#debug" do
|
26
|
+
it "passes string messages to its loggers" do
|
27
|
+
stdout_logger.should_receive(:debug).with(message)
|
28
|
+
file_logger.should_receive(:debug).with(message)
|
29
|
+
logger.debug(message)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "passes block messages to its loggers" do
|
33
|
+
stdout_logger.should_receive(:debug).with(&block)
|
34
|
+
file_logger.should_receive(:debug).with(&block)
|
35
|
+
logger.debug(&block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#error" do
|
40
|
+
it "passes string messages to its loggers" do
|
41
|
+
stdout_logger.should_receive(:error).with(message)
|
42
|
+
file_logger.should_receive(:error).with(message)
|
43
|
+
logger.error(message)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "passes block messages to its loggers" do
|
47
|
+
stdout_logger.should_receive(:error).with(&block)
|
48
|
+
file_logger.should_receive(:error).with(&block)
|
49
|
+
logger.error(&block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#warn" do
|
54
|
+
it "passes string messages to its loggers" do
|
55
|
+
stdout_logger.should_receive(:warn).with(message)
|
56
|
+
file_logger.should_receive(:warn).with(message)
|
57
|
+
logger.warn(message)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "passes block messages to its loggers" do
|
61
|
+
stdout_logger.should_receive(:warn).with(&block)
|
62
|
+
file_logger.should_receive(:warn).with(&block)
|
63
|
+
logger.warn(&block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#info" do
|
68
|
+
it "passes string messages to its loggers" do
|
69
|
+
stdout_logger.should_receive(:info).with(message)
|
70
|
+
file_logger.should_receive(:info).with(message)
|
71
|
+
logger.info(message)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "passes block messages to its loggers" do
|
75
|
+
stdout_logger.should_receive(:info).with(&block)
|
76
|
+
file_logger.should_receive(:info).with(&block)
|
77
|
+
logger.info(&block)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#fatal" do
|
82
|
+
it "passes string messages to its loggers" do
|
83
|
+
stdout_logger.should_receive(:fatal).with(message)
|
84
|
+
file_logger.should_receive(:fatal).with(message)
|
85
|
+
logger.fatal(message)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "passes block messages to its loggers" do
|
89
|
+
stdout_logger.should_receive(:fatal).with(&block)
|
90
|
+
file_logger.should_receive(:fatal).with(&block)
|
91
|
+
logger.fatal(&block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -1,10 +1,20 @@
|
|
1
1
|
require "employer/pipeline"
|
2
2
|
|
3
3
|
describe Employer::Pipeline do
|
4
|
-
let(:
|
4
|
+
let(:logger) { double("Logger").as_null_object }
|
5
|
+
let(:pipeline) { Employer::Pipeline.new(logger) }
|
5
6
|
let(:backend) { double("Pipeline backend") }
|
6
7
|
let(:job) { double("Job") }
|
7
8
|
|
9
|
+
describe "#initialize" do
|
10
|
+
let(:logger) { double("Logger") }
|
11
|
+
|
12
|
+
it "sets the logger" do
|
13
|
+
pipeline = Employer::Pipeline.new(logger)
|
14
|
+
pipeline.logger.should eq(logger)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
8
18
|
it "has a pluggable backend" do
|
9
19
|
pipeline.backend = backend
|
10
20
|
pipeline.backend.should eq(backend)
|
@@ -1,105 +1,132 @@
|
|
1
|
-
require "employer
|
1
|
+
require "employer"
|
2
2
|
|
3
3
|
describe Employer::Workshop do
|
4
4
|
before(:each) do
|
5
|
-
stub_const("Employer::Boss", Class.new)
|
6
|
-
stub_const("Employer::Pipeline", Class.new)
|
7
|
-
stub_const("Employer::Employees::ForkingEmployee", Class.new)
|
8
|
-
stub_const("Employer::Employees::ThreadingEmployee", Class.new)
|
9
5
|
stub_const("TestPipelineBackend", Class.new)
|
10
6
|
end
|
11
7
|
|
12
|
-
let(:
|
13
|
-
let(:config_code) do
|
14
|
-
<<CONFIG
|
15
|
-
pipeline_backend TestPipelineBackend.new
|
16
|
-
forking_employees 2
|
17
|
-
CONFIG
|
18
|
-
end
|
19
|
-
let(:workshop) do
|
20
|
-
Employer::Boss.should_receive(:new).and_return(boss)
|
21
|
-
Employer::Workshop.setup(config_code)
|
22
|
-
end
|
8
|
+
let(:config_code) { "pipeline_backend TestPipelineBackend.new" }
|
23
9
|
|
24
|
-
describe "
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
10
|
+
describe "#initialize" do
|
11
|
+
let(:workshop) { Employer::Workshop.new(config_code) }
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
workshop
|
15
|
+
end
|
16
|
+
|
17
|
+
it "sets up a logger" do
|
18
|
+
workshop.logger.should be_instance_of(Employer::Logger)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets up a boss" do
|
22
|
+
logger = double("Logger")
|
23
|
+
Employer::Logger.should_receive(:new).and_return(logger)
|
24
|
+
Employer::Boss.should_receive(:new).with(logger).and_call_original
|
25
|
+
end
|
35
26
|
|
27
|
+
it "sets the defined pipeline backend" do
|
28
|
+
boss = double("Boss")
|
36
29
|
Employer::Boss.should_receive(:new).and_return(boss)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
30
|
+
boss.should_receive(:pipeline_backend=).with(instance_of(TestPipelineBackend))
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with loggers" do
|
34
|
+
before(:each) do
|
35
|
+
stub_const("MyFirstLogger", Class.new)
|
36
|
+
stub_const("MySecondLogger", Class.new)
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:config_code) { "log_to MyFirstLogger.new\nlog_to MySecondLogger.new" }
|
40
|
+
|
41
|
+
it "tells the logger to append to the given logger" do
|
42
|
+
workshop_logger = double("Logger")
|
43
|
+
Employer::Logger.should_receive(:new).and_return(workshop_logger)
|
44
|
+
workshop_logger.should_receive(:append_to).with(instance_of(MyFirstLogger))
|
45
|
+
workshop_logger.should_receive(:append_to).with(instance_of(MySecondLogger))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "with only forking employees" do
|
50
|
+
let(:config_code) { "forking_employees 3" }
|
51
|
+
|
52
|
+
it "allocates forking employees" do
|
53
|
+
Employer::Employees::ForkingEmployee.should_receive(:new).with(instance_of(Employer::Logger)).exactly(3).times.and_call_original
|
54
|
+
Employer::Boss.any_instance.should_receive(:allocate_employee).with(instance_of(Employer::Employees::ForkingEmployee)).exactly(3).times
|
55
|
+
end
|
56
|
+
|
57
|
+
it "does not instantiate threading employees" do
|
58
|
+
Employer::Employees::ThreadingEmployee.should_receive(:new).never
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with only threading employees" do
|
63
|
+
let(:config_code) { "threading_employees 2" }
|
64
|
+
|
65
|
+
it "allocates threading employees" do
|
66
|
+
Employer::Employees::ThreadingEmployee.should_receive(:new).with(instance_of(Employer::Logger)).exactly(2).times.and_call_original
|
67
|
+
Employer::Boss.any_instance.should_receive(:allocate_employee).with(instance_of(Employer::Employees::ThreadingEmployee)).exactly(2).times
|
68
|
+
end
|
69
|
+
|
70
|
+
it "does not instantiate forking employees" do
|
71
|
+
Employer::Employees::ForkingEmployee.should_receive(:new).never
|
72
|
+
end
|
57
73
|
end
|
58
74
|
end
|
59
75
|
|
60
76
|
describe ".pipeline" do
|
61
|
-
it "
|
62
|
-
|
63
|
-
Employer::
|
64
|
-
pipeline = double("Pipeline").as_null_object
|
65
|
-
boss.stub(:pipeline).and_return(pipeline)
|
66
|
-
Employer::Pipeline.should_receive(:new).and_return(pipeline)
|
67
|
-
pipeline_backend = double("Pipeline backend")
|
68
|
-
TestPipelineBackend.should_receive(:new).and_return(pipeline_backend)
|
77
|
+
it "returns a pipeline to feed the workshop" do
|
78
|
+
Employer::Pipeline.should_receive(:new).and_call_original
|
79
|
+
Employer::Pipeline.any_instance.should_receive(:backend=).with(instance_of(TestPipelineBackend)).and_call_original
|
69
80
|
File.should_receive(:read).with("config/employee.rb").and_return(config_code)
|
70
|
-
|
71
81
|
workshop_pipeline = Employer::Workshop.pipeline("config/employee.rb")
|
72
|
-
workshop_pipeline.should
|
82
|
+
workshop_pipeline.should be_instance_of(Employer::Pipeline)
|
73
83
|
end
|
74
84
|
end
|
75
85
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
86
|
+
context "with initialized workshop" do
|
87
|
+
let(:workshop) { Employer::Workshop.new(config_code) }
|
88
|
+
let(:boss) { Employer::Boss.any_instance }
|
89
|
+
|
90
|
+
describe "#logger" do
|
91
|
+
it "returns the logger" do
|
92
|
+
workshop.logger.should be_instance_of(Employer::Logger)
|
93
|
+
end
|
80
94
|
end
|
81
|
-
end
|
82
95
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
96
|
+
describe "#run" do
|
97
|
+
it "should call manage on the boss" do
|
98
|
+
boss.should_receive(:manage)
|
99
|
+
workshop.run
|
100
|
+
end
|
87
101
|
end
|
88
|
-
end
|
89
102
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
103
|
+
describe "#stop" do
|
104
|
+
it "should call stop_managing on the boss" do
|
105
|
+
boss.should_receive(:stop_managing)
|
106
|
+
workshop.stop
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#stop_now" do
|
111
|
+
it "should call stop_managing and stop_employees on the boss" do
|
112
|
+
boss.should_receive(:stop_managing)
|
113
|
+
boss.should_receive(:stop_employees)
|
114
|
+
workshop.stop_now
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#pipeline" do
|
119
|
+
it "returns the pipeline" do
|
120
|
+
workshop.pipeline.should be_instance_of(Employer::Pipeline)
|
121
|
+
end
|
95
122
|
end
|
96
|
-
end
|
97
123
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
124
|
+
describe "#log_to" do
|
125
|
+
it "adds a logger to the workshop logger" do
|
126
|
+
logger = double("Logger")
|
127
|
+
workshop.logger.should_receive(:append_to).with(logger)
|
128
|
+
workshop.log_to(logger)
|
129
|
+
end
|
103
130
|
end
|
104
131
|
end
|
105
132
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
shared_examples "an employee" do
|
2
|
-
let(:
|
2
|
+
let(:logger) { double("Logger").as_null_object }
|
3
|
+
let(:employee) { described_class.new(logger) }
|
3
4
|
let(:completing_job_class) do
|
4
5
|
Class.new do
|
5
6
|
def perform
|
@@ -19,6 +20,13 @@ shared_examples "an employee" do
|
|
19
20
|
let(:failing_job) { failing_job_class.new}
|
20
21
|
let(:job) { double("Job") }
|
21
22
|
|
23
|
+
describe "#initialize" do
|
24
|
+
it "sets the logger" do
|
25
|
+
employee = described_class.new(logger)
|
26
|
+
employee.logger.should eq(logger)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
22
30
|
describe "#work" do
|
23
31
|
it "rejects a job while its already working on one" do
|
24
32
|
employee.should_receive(:free?).and_return(false)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: employer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.3'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.17'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
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'
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: rspec
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,6 +86,7 @@ files:
|
|
70
86
|
- .gitignore
|
71
87
|
- .pryrc
|
72
88
|
- .rspec
|
89
|
+
- .travis.yml
|
73
90
|
- Gemfile
|
74
91
|
- LICENSE.txt
|
75
92
|
- README.md
|
@@ -90,6 +107,7 @@ files:
|
|
90
107
|
- lib/employer/errors/no_employee_free.rb
|
91
108
|
- lib/employer/errors/pipeline_backend_required.rb
|
92
109
|
- lib/employer/job.rb
|
110
|
+
- lib/employer/logger.rb
|
93
111
|
- lib/employer/pipeline.rb
|
94
112
|
- lib/employer/version.rb
|
95
113
|
- lib/employer/workshop.rb
|
@@ -97,6 +115,7 @@ files:
|
|
97
115
|
- spec/employer/employees/forking_employee_spec.rb
|
98
116
|
- spec/employer/employees/threading_employee_spec.rb
|
99
117
|
- spec/employer/job_spec.rb
|
118
|
+
- spec/employer/logger_spec.rb
|
100
119
|
- spec/employer/pipeline_spec.rb
|
101
120
|
- spec/employer/workshop_spec.rb
|
102
121
|
- spec/spec_helper.rb
|
@@ -114,23 +133,30 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
133
|
- - ! '>='
|
115
134
|
- !ruby/object:Gem::Version
|
116
135
|
version: '0'
|
136
|
+
segments:
|
137
|
+
- 0
|
138
|
+
hash: 2766441661319471233
|
117
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
140
|
none: false
|
119
141
|
requirements:
|
120
142
|
- - ! '>='
|
121
143
|
- !ruby/object:Gem::Version
|
122
144
|
version: '0'
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
hash: 2766441661319471233
|
123
148
|
requirements: []
|
124
149
|
rubyforge_project:
|
125
150
|
rubygems_version: 1.8.23
|
126
151
|
signing_key:
|
127
152
|
specification_version: 3
|
128
|
-
summary: Job processing made easy
|
153
|
+
summary: Job processing with pluggable backends made easy
|
129
154
|
test_files:
|
130
155
|
- spec/employer/boss_spec.rb
|
131
156
|
- spec/employer/employees/forking_employee_spec.rb
|
132
157
|
- spec/employer/employees/threading_employee_spec.rb
|
133
158
|
- spec/employer/job_spec.rb
|
159
|
+
- spec/employer/logger_spec.rb
|
134
160
|
- spec/employer/pipeline_spec.rb
|
135
161
|
- spec/employer/workshop_spec.rb
|
136
162
|
- spec/spec_helper.rb
|