actionable 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +9 -6
- data/lib/actionable/job.rb +35 -8
- data/lib/actionable/mongoid_store/action.rb +4 -2
- data/lib/actionable/version.rb +1 -1
- data/spec/failure_spec.rb +86 -0
- data/spec/job_spec.rb +30 -11
- data/spec/spec_helper.rb +12 -4
- data/spec/support/test_failure_job.rb +15 -0
- data/spec/support/test_job.rb +4 -1
- data/spec/support/test_model.rb +2 -2
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c16c458ffbb1eb2bbbfde2247d0d86fbfe298bad
|
4
|
+
data.tar.gz: 8b991e118cc9296f7e5a672a50f099b67bb64778
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea836f60b3bf4e816216e2134110d9682042793e7f3ea3a90745ddd43c0ec40191e1808ece4a67c793757c05a1ca6c97b2d4d278559f29d4bad1aadd195c3b41
|
7
|
+
data.tar.gz: 79f948b69c68e3c3e9b3a85ab57048d33755a3d323d378ba9707cf315c8ca8a279221f570519cf43f079a7487430c7d686370d30cf70329ee989ea0b381766cf
|
data/Rakefile
CHANGED
@@ -4,19 +4,22 @@ require 'resque/tasks'
|
|
4
4
|
require 'rspec/core/rake_task'
|
5
5
|
|
6
6
|
task "resque:setup" do
|
7
|
-
|
8
|
-
Dir[File.expand_path('../spec/support/*.rb', __FILE__)].each do |f|
|
9
|
-
puts f
|
7
|
+
|
8
|
+
Dir[File.expand_path('../spec/support/*.rb', __FILE__)].each do |f|
|
10
9
|
require f
|
11
10
|
end
|
12
11
|
|
13
|
-
puts TestJob.class.to_s
|
14
12
|
Mongoid.configure do |config|
|
15
13
|
config.connect_to('actionable_test')
|
16
14
|
end
|
15
|
+
|
17
16
|
end
|
18
17
|
|
19
18
|
|
20
|
-
|
19
|
+
task :spec do
|
20
|
+
Dir['spec/*_spec.rb'] .each do |f|
|
21
|
+
system("rspec #{f}")
|
22
|
+
end
|
23
|
+
end
|
21
24
|
|
22
|
-
task :default => :spec
|
25
|
+
task :default => :spec
|
data/lib/actionable/job.rb
CHANGED
@@ -1,22 +1,49 @@
|
|
1
1
|
module Actionable
|
2
2
|
class Job
|
3
|
-
|
3
|
+
|
4
4
|
attr_reader :actionable, :target, :payload
|
5
5
|
|
6
|
+
def self.logger
|
7
|
+
defined?(Rails) ? Rails.logger : Resque.logger
|
8
|
+
end
|
9
|
+
|
10
|
+
def logger
|
11
|
+
self.class.logger
|
12
|
+
end
|
13
|
+
|
6
14
|
def self.queue
|
7
15
|
@queue ||= 'actionable'
|
8
16
|
end
|
9
17
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
18
|
+
def self.before_enqueue(id)
|
19
|
+
actionable = Actionable::Action.find(id)
|
20
|
+
actionable.update_attributes(status: :enqueued)
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.on_failure(err,id)
|
25
|
+
begin
|
26
|
+
actionable = Actionable::Action.find(id)
|
27
|
+
actionable.update_attributes({
|
28
|
+
status: :failed,
|
29
|
+
exception_message: err.message,
|
30
|
+
exception_backtrace: err.backtrace
|
31
|
+
})
|
32
|
+
job = new(actionable.target,actionable.payload,actionable)
|
33
|
+
job.on_failure(err) if job.respond_to?(:on_failure)
|
34
|
+
rescue => e
|
35
|
+
puts "Error in 'on_failure' handler: #{e.message}"
|
36
|
+
logger.error("Error in 'on_failure' handler: #{e.message}")
|
37
|
+
end
|
38
|
+
end
|
14
39
|
|
15
40
|
def self.perform(id)
|
16
41
|
actionable = Actionable::Action.find(id)
|
17
42
|
actionable.update_attributes(status: :working)
|
18
|
-
new(actionable.target,actionable.payload,actionable)
|
43
|
+
job = new(actionable.target,actionable.payload,actionable)
|
44
|
+
job.perform
|
19
45
|
actionable.update_attributes(status: :complete)
|
46
|
+
job.on_success if job.respond_to?(:on_success)
|
20
47
|
end
|
21
48
|
|
22
49
|
def initialize(target,payload={},actionable=nil)
|
@@ -24,6 +51,6 @@ module Actionable
|
|
24
51
|
@actionable = actionable
|
25
52
|
@payload = HashWithIndifferentAccess.new(payload)
|
26
53
|
end
|
27
|
-
|
54
|
+
|
28
55
|
end
|
29
|
-
end
|
56
|
+
end
|
@@ -9,15 +9,17 @@ module Actionable
|
|
9
9
|
store_in(collection: 'actionables')
|
10
10
|
|
11
11
|
after_initialize :flag_late
|
12
|
-
|
12
|
+
|
13
13
|
field :execution_time, type: Time
|
14
14
|
field :payload, type: Hash
|
15
15
|
field :job_class_name, type: String
|
16
16
|
field :status, type: Symbol, default: :new
|
17
17
|
field :target_id, type: Moped::BSON::ObjectId
|
18
18
|
field :target_class_name, type: String
|
19
|
+
field :exception_message, type: String
|
20
|
+
field :exception_backtrace, type: Array
|
19
21
|
|
20
|
-
scope :scheduled_for_between, ->(from,to){
|
22
|
+
scope :scheduled_for_between, ->(from,to){
|
21
23
|
between(execution_time:[from,to])
|
22
24
|
}
|
23
25
|
scope :scheduled_for_before, ->(to){ where(:execution_time.lt => to) }
|
data/lib/actionable/version.rb
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class TestWorker
|
4
|
+
|
5
|
+
attr_accessor :pid
|
6
|
+
|
7
|
+
def spawn
|
8
|
+
@pid = Kernel.spawn('bundle exec rake resque:work QUEUES=actionable,actionable_sweep')
|
9
|
+
end
|
10
|
+
|
11
|
+
def kill
|
12
|
+
system("killall resque-1.24.1: Waiting for actionable,actionable_sweep")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_test_worker(id)
|
18
|
+
w = TestWorker.new
|
19
|
+
w.spawn
|
20
|
+
poll_for_finished(id)
|
21
|
+
w.kill
|
22
|
+
end
|
23
|
+
|
24
|
+
def poll_for_finished(id)
|
25
|
+
until TestModel.find(id).actionables.first.reload.status == :failed
|
26
|
+
sleep(1)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "Failing Actionable::Job" do
|
31
|
+
|
32
|
+
before do
|
33
|
+
system('killall resque-1.24.1: Waiting for actionable,actionable_sweep')
|
34
|
+
end
|
35
|
+
|
36
|
+
after do
|
37
|
+
system('killall resque-1.24.1: Waiting for actionable,actionable_sweep')
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
context "scheduled for one minute ago" do
|
42
|
+
|
43
|
+
it "should be executed by a worker manually" do
|
44
|
+
Resque.inline = true
|
45
|
+
target = TestModel.create({
|
46
|
+
color:'blue',
|
47
|
+
shape:'square',
|
48
|
+
number:3
|
49
|
+
})
|
50
|
+
target.schedule_actionable(1.minute.ago,TestFailureJob,{number:2})
|
51
|
+
id = target.id
|
52
|
+
expect(TestFailureJob).to receive(:on_fail)
|
53
|
+
# expect(Resque::Failure).to receive(:create)
|
54
|
+
expect {
|
55
|
+
Actionable::Sweep.perform
|
56
|
+
}.to raise_error(StandardError)
|
57
|
+
expect(TestModel.find(id).number).to_not eq(6)
|
58
|
+
expect(TestModel.find(id).name).to_not eq('blue square')
|
59
|
+
expect(Actionable::Action.last.status).to eq(:failed)
|
60
|
+
expect(Actionable::Action.last.exception_message).to eq('This is my error')
|
61
|
+
Resque.inline = false
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should be executed by a worker in another processes", :no do
|
65
|
+
target = TestModel.create({
|
66
|
+
color:'blue',
|
67
|
+
shape:'square',
|
68
|
+
number:3
|
69
|
+
})
|
70
|
+
target.schedule_actionable(1.minute.ago,TestFailureJob,{number:2})
|
71
|
+
id = target.id
|
72
|
+
run_test_worker(id)
|
73
|
+
expect(TestModel.find(id).number).to_not eq(6)
|
74
|
+
expect(TestModel.find(id).name).to_not eq('blue square')
|
75
|
+
expect(Actionable::Action.last.status).to eq(:failed)
|
76
|
+
expect(Actionable::Action.last.exception_message).to eq('This is my error')
|
77
|
+
|
78
|
+
error_json = Redis.new.rpop('resque:failed')
|
79
|
+
error_hash = JSON.load(error_json)
|
80
|
+
expect(error_hash.fetch('error')).to eq("This is my error")
|
81
|
+
expect(error_hash.fetch('payload').fetch('args').first.to_s).to eq(Actionable::Action.last.id.to_s)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/spec/job_spec.rb
CHANGED
@@ -9,7 +9,7 @@ class TestWorker
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def kill
|
12
|
-
system(
|
12
|
+
system('killall resque-1.24.1: Waiting for actionable,actionable_sweep')
|
13
13
|
end
|
14
14
|
|
15
15
|
end
|
@@ -29,34 +29,53 @@ end
|
|
29
29
|
|
30
30
|
describe Actionable::Job do
|
31
31
|
|
32
|
+
before do
|
33
|
+
system('killall resque-1.24.1: Waiting for actionable,actionable_sweep')
|
34
|
+
end
|
35
|
+
|
36
|
+
after do
|
37
|
+
system('killall resque-1.24.1: Waiting for actionable,actionable_sweep')
|
38
|
+
end
|
39
|
+
|
32
40
|
context "scheduled for one minute ago" do
|
33
41
|
|
34
|
-
|
35
|
-
|
42
|
+
it "should be executed by a worker manually" do
|
43
|
+
DOUBLE = double()
|
44
|
+
expect(DOUBLE).to receive(:success)
|
45
|
+
|
46
|
+
def TestJob.on_success(s)
|
47
|
+
DOUBLE.success
|
48
|
+
end
|
49
|
+
|
50
|
+
Resque.inline = true
|
51
|
+
target = TestModel.create({
|
36
52
|
color:'blue',
|
37
53
|
shape:'square',
|
38
54
|
number:3
|
39
55
|
})
|
40
|
-
|
41
|
-
|
42
|
-
before do
|
43
|
-
target.schedule_actionable(1.minute.ago,TestJob,{number:2})
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should be executed by a worker manually" do
|
47
|
-
Resque.inline = true
|
56
|
+
target.schedule_actionable(1.minute.ago,TestJob,{number:2})
|
48
57
|
id = target.id
|
58
|
+
|
49
59
|
Actionable::Sweep.perform
|
50
60
|
expect(TestModel.find(id).number).to eq(6)
|
51
61
|
expect(TestModel.find(id).name).to eq('blue square')
|
62
|
+
expect(Actionable::Action.last.status).to eq(:complete)
|
52
63
|
Resque.inline = false
|
53
64
|
end
|
54
65
|
|
55
66
|
it "should be executed by a worker in another processes", :no do
|
67
|
+
target = TestModel.create({
|
68
|
+
color:'blue',
|
69
|
+
shape:'square',
|
70
|
+
number:3
|
71
|
+
})
|
72
|
+
target.schedule_actionable(1.minute.ago,TestJob,{number:2})
|
56
73
|
id = target.id
|
57
74
|
run_test_worker(id)
|
58
75
|
expect(TestModel.find(id).number).to eq(6)
|
59
76
|
expect(TestModel.find(id).name).to eq('blue square')
|
77
|
+
|
78
|
+
|
60
79
|
end
|
61
80
|
|
62
81
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,26 +1,34 @@
|
|
1
1
|
require "bundler"
|
2
2
|
Bundler.require(:default,:development)
|
3
|
-
|
3
|
+
|
4
4
|
Dir[File.expand_path('../support/*.rb', __FILE__)].each {|f| require f}
|
5
5
|
|
6
6
|
Mongoid.configure do |config|
|
7
7
|
config.connect_to('actionable_test')
|
8
8
|
end
|
9
9
|
|
10
|
-
Resque.redis = Redis.new
|
11
|
-
Resque.redis.namespace = "resque:actionable_test:"
|
12
|
-
|
13
10
|
module Resque
|
14
11
|
def self.purge!
|
15
12
|
self.redis.keys('*')
|
16
13
|
self.redis.del(*keys) unless keys.count == 0
|
17
14
|
end
|
15
|
+
# def failure_count
|
16
|
+
# Resque.redis = Redis.new
|
17
|
+
# count = Resque::Failure.count
|
18
|
+
# Resque.redis.namespace = "resque:actionable_test:"
|
19
|
+
# count
|
20
|
+
# end
|
18
21
|
end
|
19
22
|
|
20
23
|
RSpec.configure do |config|
|
21
24
|
|
22
25
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
23
26
|
|
27
|
+
config.before(:each) do
|
28
|
+
Resque.redis = Redis.new
|
29
|
+
Resque.redis.namespace = "resque:actionable_test:"
|
30
|
+
end
|
31
|
+
|
24
32
|
config.after(:each) do
|
25
33
|
Resque.purge!
|
26
34
|
Mongoid.purge!
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class TestFailureJob < Actionable::Job
|
2
|
+
|
3
|
+
def perform
|
4
|
+
target.name = target.say_something
|
5
|
+
raise StandardError.new('This is my error')
|
6
|
+
target.number = target.number * payload[:number]
|
7
|
+
target.save
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_failure(err)
|
11
|
+
self.class.on_fail
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
end
|
data/spec/support/test_job.rb
CHANGED
data/spec/support/test_model.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Luxemburg
|
@@ -205,10 +205,12 @@ files:
|
|
205
205
|
- lib/actionable/tasks.rb
|
206
206
|
- lib/actionable/version.rb
|
207
207
|
- spec/action_spec.rb
|
208
|
+
- spec/failure_spec.rb
|
208
209
|
- spec/job_spec.rb
|
209
210
|
- spec/recurrence_spec.rb
|
210
211
|
- spec/spec_helper.rb
|
211
212
|
- spec/support/recurring_test_job.rb
|
213
|
+
- spec/support/test_failure_job.rb
|
212
214
|
- spec/support/test_job.rb
|
213
215
|
- spec/support/test_model.rb
|
214
216
|
- spec/sweep_spec.rb
|
@@ -240,10 +242,12 @@ summary: Store stuff in Mongo, keep track of it in Redis, log lots of stuff, inc
|
|
240
242
|
test help
|
241
243
|
test_files:
|
242
244
|
- spec/action_spec.rb
|
245
|
+
- spec/failure_spec.rb
|
243
246
|
- spec/job_spec.rb
|
244
247
|
- spec/recurrence_spec.rb
|
245
248
|
- spec/spec_helper.rb
|
246
249
|
- spec/support/recurring_test_job.rb
|
250
|
+
- spec/support/test_failure_job.rb
|
247
251
|
- spec/support/test_job.rb
|
248
252
|
- spec/support/test_model.rb
|
249
253
|
- spec/sweep_spec.rb
|