actionable 0.1.0 → 0.1.1
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 +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
|