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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b187586cc793a33104a2f5c1710daefae5d25023
4
- data.tar.gz: 77797479469c0474aa59cc8c545160086ba50033
3
+ metadata.gz: c16c458ffbb1eb2bbbfde2247d0d86fbfe298bad
4
+ data.tar.gz: 8b991e118cc9296f7e5a672a50f099b67bb64778
5
5
  SHA512:
6
- metadata.gz: 535ef546df907bbdc4eb4b1564bf8272185cd8724842394f216f25c98f0dd77c65111add75475a412ebc88f945453f2e4a11d39659da394d3b144472a7479ec1
7
- data.tar.gz: dd8b4beee3770047d760f8f126907358407931d072e9eca60825b2cc43d177e5c229ca2d7ab90b50e6e5a40eca5e7ac481f1cc388f17b4e9f9aa0e9b5c15ddcb
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
- puts File.expand_path('../spec/support/*.rb', __FILE__)
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
- RSpec::Core::RakeTask.new(:spec)
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
@@ -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
- # def self.after_enqueue(id)
11
- # actionable = Actionable::Action.find(id)
12
- # actionable.update_attributes(status: :enqueued)
13
- # end
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).perform
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) }
@@ -1,3 +1,3 @@
1
1
  module Actionable
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -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
@@ -9,7 +9,7 @@ class TestWorker
9
9
  end
10
10
 
11
11
  def kill
12
- system("kill -9 #{pid}")
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
- let(:target) {
35
- TestModel.create({
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
@@ -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
@@ -6,5 +6,8 @@ class TestJob < Actionable::Job
6
6
  target.save
7
7
  end
8
8
 
9
+ def on_success
10
+ self.class.on_success(self)
11
+ end
9
12
 
10
- end
13
+ end
@@ -8,8 +8,8 @@ class TestModel
8
8
  field :shape
9
9
  field :number
10
10
 
11
- def say_something
11
+ def say_something(arg = nil)
12
12
  return "#{color} #{shape}"
13
13
  end
14
14
 
15
- end
15
+ end
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.0
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