acts_as_executor 1.0.0.rc1 → 1.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/README.markdown +97 -0
- data/Rakefile +5 -0
- data/acts_as_executor.gemspec +7 -1
- data/lib/acts_as_executor.rb +2 -2
- data/lib/acts_as_executor/common/instance_support_methods.rb +2 -2
- data/lib/acts_as_executor/executor/model/instance_methods.rb +9 -9
- data/lib/acts_as_executor/task/{clazz.rb → executable.rb} +1 -1
- data/lib/acts_as_executor/task/model/instance_methods.rb +6 -6
- data/lib/acts_as_executor/validators/class_subclasses_validator.rb +11 -0
- data/lib/acts_as_executor/version.rb +1 -1
- data/lib/generators/acts_as_executor/executable/executable_generator.rb +9 -0
- data/lib/generators/acts_as_executor/executable/templates/executables/executable.rb +5 -0
- data/lib/generators/acts_as_executor/install/install_generator.rb +20 -0
- data/lib/generators/{templates → acts_as_executor/install/templates}/migration/create_executors.rb +1 -1
- data/lib/generators/{templates → acts_as_executor/install/templates}/models/executor.rb +0 -0
- data/lib/generators/{templates → acts_as_executor/install/templates}/models/executor_task.rb +0 -0
- data/spec/acts_as_executor_spec.rb +1 -1
- data/spec/common/future_task_spec.rb +1 -1
- data/spec/common/instance_support_methods_spec.rb +2 -2
- data/spec/executor/model/instance_methods_spec.rb +19 -19
- data/spec/support/blueprints.rb +4 -4
- data/spec/support/classes.rb +4 -5
- data/spec/support/custom_matchers.rb +2 -2
- data/spec/task/{clazz_spec.rb → executable_spec.rb} +2 -2
- data/spec/task/model/instance_methods_spec.rb +10 -10
- data/spec/validators/class_exists_validator_spec.rb +1 -1
- data/spec/validators/class_subclasses_validator_spec.rb +21 -0
- metadata +19 -15
- data/lib/acts_as_executor/validators/class_includes_validator.rb +0 -10
- data/lib/generators/acts_as_executor_generator.rb +0 -18
- data/spec/validators/class_includes_validator_spec.rb +0 -21
data/.rspec
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# acts_as_executor
|
2
|
+
|
3
|
+
acts_as_executor seamlessly integrates Java’s Executor framework with JRuby on Rails, enabling an application to use executors in a familiar Rails’eque way.
|
4
|
+
|
5
|
+
[RubyGems][ruby_gems] | [GitHub][github] | [Travis CI][travis_ci] | [RubyDoc][ruby_doc] | [Wiki][wiki]
|
6
|
+
|
7
|
+
## Features
|
8
|
+
* **Abstraction** from low-level executor type configuration
|
9
|
+
* **ActiveRecord** interface so creating an executor or task is as simple is creating a record
|
10
|
+
* **Automatic Task Setup** so you can concentrate on business logic and not task management
|
11
|
+
* **Database Persisted Configuration** so executors can be managed through migrations and seeds
|
12
|
+
* **Logging** of executor and task states to Rails or custom logger
|
13
|
+
|
14
|
+
## 1. Install
|
15
|
+
```ruby
|
16
|
+
gem "acts_as_executor"
|
17
|
+
```
|
18
|
+
...or for life on the edge, use the [master branch][github_master] [![Build Status][travis_ci_build_status]][travis_ci]
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem "acts_as_executor", :git => "git@github.com:philostler/acts_as_executor.git"
|
22
|
+
```
|
23
|
+
|
24
|
+
## 2. Generate
|
25
|
+
Generate models and migration using...
|
26
|
+
|
27
|
+
```
|
28
|
+
rails g acts_as_executor:install <model_name>
|
29
|
+
```
|
30
|
+
|
31
|
+
Example
|
32
|
+
|
33
|
+
```
|
34
|
+
rails g acts_as_executor:install Executor
|
35
|
+
create app/models/executor.rb
|
36
|
+
create app/models/executor_task.rb
|
37
|
+
create db/migrate/20110922223408_create_executors.rb
|
38
|
+
```
|
39
|
+
|
40
|
+
## 3. Execute!
|
41
|
+
You'll first need to create an executor to schedule tasks upon.
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
Executor.create :name => "background"
|
45
|
+
```
|
46
|
+
|
47
|
+
These can be created on the fly at runtime (be sure to save the record before you schedule any tasks) or preconfigured via records already present in the database. The recommended method is to add the applications required executors to the database seed file and running ```rake db:seed```.
|
48
|
+
|
49
|
+
Attributes ```max_tasks``` and ```schedulable``` exist on the executors model for task limiting and schedulable ability enabling. Check out the wiki documentation for details of how these work.
|
50
|
+
|
51
|
+
[Using Executors][wiki_using_executors]
|
52
|
+
|
53
|
+
Once you have an executor available, it's time to add some tasks. Do this like you would any associated record.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
Executor.find_by_name("background").tasks.create(:executable => "BackgroundTask",
|
57
|
+
:arguments => { :data => "This is my data"})
|
58
|
+
```
|
59
|
+
|
60
|
+
The ```executable``` attribute references a class that must...
|
61
|
+
|
62
|
+
* Be available in the load path
|
63
|
+
* Subclass ```ActsAsExecutor::Task::Executable```
|
64
|
+
* Define an ```execute``` method
|
65
|
+
|
66
|
+
Use the provided generator to create new executables...
|
67
|
+
|
68
|
+
```
|
69
|
+
rails g acts_as_executor:executable <executable_name>
|
70
|
+
```
|
71
|
+
|
72
|
+
Example
|
73
|
+
|
74
|
+
```
|
75
|
+
rails g acts_as_executor:executable Executable
|
76
|
+
create app/executables/executable.rb
|
77
|
+
```
|
78
|
+
|
79
|
+
Anything passed into the ```attributes``` hash will be available to the instance when it is executed.
|
80
|
+
|
81
|
+
Attributes ```schedule```, ```start```, ```every``` and ```units``` exist on the tasks model for defining the type and periods for scheduling and their units. Check out the wiki documentation for details of how these work.
|
82
|
+
|
83
|
+
[Using Tasks][wiki_using_tasks]
|
84
|
+
|
85
|
+
## Compatibility
|
86
|
+
* JRuby 1.6.x (1.8.7 and 1.9.2 modes)
|
87
|
+
* Rails 3.x
|
88
|
+
|
89
|
+
[github]: https://github.com/philostler/acts_as_executor
|
90
|
+
[github_master]: https://github.com/philostler/acts_as_executor/tree/master
|
91
|
+
[ruby_doc]: http://rubydoc.info/github/philostler/acts_as_executor/master/frames
|
92
|
+
[ruby_gems]: http://rubygems.org/gems/acts_as_executor
|
93
|
+
[travis_ci]: http://travis-ci.org/philostler/acts_as_executor
|
94
|
+
[travis_ci_build_status]: https://secure.travis-ci.org/philostler/acts_as_executor.png
|
95
|
+
[wiki]: https://github.com/philostler/acts_as_executor/wiki
|
96
|
+
[wiki_using_executors]: https://github.com/philostler/acts_as_executor/wiki/Using-Executors
|
97
|
+
[wiki_using_tasks]: https://github.com/philostler/acts_as_executor/wiki/Using-Tasks
|
data/Rakefile
ADDED
data/acts_as_executor.gemspec
CHANGED
@@ -12,7 +12,13 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = %q{Java Executor framework integration for Rails}
|
13
13
|
s.description = %q{Seamlessly integrates Java's Executor framework with JRuby on Rails}
|
14
14
|
|
15
|
-
s.files
|
15
|
+
s.files = Dir[".rspec"] +
|
16
|
+
Dir["acts_as_executor.gemspec"] +
|
17
|
+
Dir["Gemfile"] +
|
18
|
+
Dir["LICENSE"] +
|
19
|
+
Dir["Rakefile"] +
|
20
|
+
Dir["README.markdown"] +
|
21
|
+
Dir["**/*.rb"]
|
16
22
|
s.require_paths = ["lib"]
|
17
23
|
|
18
24
|
s.add_dependency "activemodel", ">= 3.0"
|
data/lib/acts_as_executor.rb
CHANGED
@@ -13,7 +13,7 @@ require "acts_as_executor/executor/model/class_methods"
|
|
13
13
|
require "acts_as_executor/executor/model/instance_methods"
|
14
14
|
require "acts_as_executor/executor/model/instance_support_methods"
|
15
15
|
|
16
|
-
require "acts_as_executor/task/
|
16
|
+
require "acts_as_executor/task/executable"
|
17
17
|
require "acts_as_executor/task/schedules"
|
18
18
|
|
19
19
|
require "acts_as_executor/task/model/class_methods"
|
@@ -21,7 +21,7 @@ require "acts_as_executor/task/model/instance_methods"
|
|
21
21
|
require "acts_as_executor/task/model/instance_support_methods"
|
22
22
|
|
23
23
|
require "acts_as_executor/validators/class_exists_validator"
|
24
|
-
require "acts_as_executor/validators/
|
24
|
+
require "acts_as_executor/validators/class_subclasses_validator"
|
25
25
|
|
26
26
|
ActiveRecord::Base.send :extend, ActsAsExecutor::Executor::Model::ClassMethods
|
27
27
|
ActiveRecord::Base.send :extend, ActsAsExecutor::Task::Model::ClassMethods
|
@@ -6,9 +6,9 @@ module ActsAsExecutor
|
|
6
6
|
"\"" + executor_name + "\" " + statement
|
7
7
|
end
|
8
8
|
|
9
|
-
def log_message executor_name, doing, task_id,
|
9
|
+
def log_message executor_name, doing, task_id, executable_name, message = ""
|
10
10
|
if message.kind_of? Hash then message = "with \"" + message.inspect + "\"" end
|
11
|
-
"\"" + executor_name + "\" " + doing + " \"" + task_id + "#" +
|
11
|
+
"\"" + executor_name + "\" " + doing + " \"" + task_id + "#" + executable_name + "\" " + message
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -25,32 +25,32 @@ module ActsAsExecutor
|
|
25
25
|
tasks.all
|
26
26
|
end
|
27
27
|
|
28
|
-
def execute
|
28
|
+
def execute instance, task_id, schedule = nil, start = nil, every = nil, units = nil
|
29
29
|
begin
|
30
30
|
humanized_schedule = schedule ? schedule.gsub("_", " ") : "one time"
|
31
|
-
log.debug log_message name, "preparing", task_id,
|
31
|
+
log.debug log_message name, "preparing", task_id, instance.class.name, "for execution (" + humanized_schedule + ")"
|
32
32
|
|
33
33
|
if schedulable?
|
34
34
|
units = Java::java.util.concurrent.TimeUnit.value_of(units.upcase)
|
35
35
|
case schedule
|
36
36
|
when ActsAsExecutor::Task::Schedules::ONE_SHOT
|
37
|
-
future = executor.schedule
|
37
|
+
future = executor.schedule instance, start, units
|
38
38
|
when ActsAsExecutor::Task::Schedules::FIXED_DELAY
|
39
|
-
future = executor.schedule_with_fixed_delay
|
39
|
+
future = executor.schedule_with_fixed_delay instance, start, every, units
|
40
40
|
when ActsAsExecutor::Task::Schedules::FIXED_RATE
|
41
|
-
future = executor.schedule_at_fixed_rate
|
41
|
+
future = executor.schedule_at_fixed_rate instance, start, every, units
|
42
42
|
end
|
43
43
|
else
|
44
|
-
future = ActsAsExecutor::Common::FutureTask.new
|
44
|
+
future = ActsAsExecutor::Common::FutureTask.new instance, nil
|
45
45
|
executor.execute future
|
46
46
|
end
|
47
47
|
|
48
|
-
log.info log_message name, "enqueued", task_id,
|
48
|
+
log.info log_message name, "enqueued", task_id, instance.class.name
|
49
49
|
future
|
50
50
|
rescue Java::java.util.concurrent.RejectedExecutionException
|
51
|
-
log.warn log_message name, "preparing", task_id,
|
51
|
+
log.warn log_message name, "preparing", task_id, instance.class.name, "encountered a rejected execution exception"
|
52
52
|
rescue Exception => exception
|
53
|
-
log.error log_message name, "preparing", task_id,
|
53
|
+
log.error log_message name, "preparing", task_id, instance.class.name, "encountered an unexpected exception. " + exception.to_s
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -16,7 +16,7 @@ module ActsAsExecutor
|
|
16
16
|
|
17
17
|
# Validations
|
18
18
|
base.validates :executor_id, :presence => true
|
19
|
-
base.validates :
|
19
|
+
base.validates :executable, :presence => true, :class_exists => true, :class_subclasses => { :superclass => ActsAsExecutor::Task::Executable }
|
20
20
|
base.validates :schedule, :inclusion => { :in => ActsAsExecutor::Task::Schedules::ALL }, :if => "executor and executor.schedulable?"
|
21
21
|
base.validates :start, :numericality => { :only_integer => true, :greater_than_or_equal_to => 0 }, :if => "executor and executor.schedulable?"
|
22
22
|
base.validates :every, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1 }, :if => "executor and executor.schedulable? and schedule != ActsAsExecutor::Task::Schedules::ONE_SHOT"
|
@@ -26,14 +26,14 @@ module ActsAsExecutor
|
|
26
26
|
private
|
27
27
|
def enqueue
|
28
28
|
begin
|
29
|
-
executor.send(:log).debug log_message executor.name, "creating", id.to_s,
|
29
|
+
executor.send(:log).debug log_message executor.name, "creating", id.to_s, executable, arguments
|
30
30
|
|
31
|
-
instance = instantiate
|
31
|
+
instance = instantiate executable, arguments
|
32
32
|
|
33
33
|
self.future = executor.send(:execute, instance, id.to_s, schedule, start, every, units)
|
34
34
|
future.done_handler = method :done_handler
|
35
35
|
rescue Exception => exception
|
36
|
-
executor.send(:log).error log_message executor.name, "creating", id.to_s,
|
36
|
+
executor.send(:log).error log_message executor.name, "creating", id.to_s, executable, "encountered an unexpected exception. " + exception.to_s
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -45,12 +45,12 @@ module ActsAsExecutor
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def done_handler
|
48
|
-
executor.send(:log).debug log_message executor.name, "completed", id.to_s,
|
48
|
+
executor.send(:log).debug log_message executor.name, "completed", id.to_s, executable
|
49
49
|
destroy
|
50
50
|
end
|
51
51
|
|
52
52
|
def uncaught_exception_handler exception
|
53
|
-
executor.send(:log).error log_message executor.name, "executing", id.to_s,
|
53
|
+
executor.send(:log).error log_message executor.name, "executing", id.to_s, executable, "encountered an uncaught exception. " + exception.to_s
|
54
54
|
end
|
55
55
|
|
56
56
|
def cancel
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ClassSubclassesValidator < ActiveModel::EachValidator
|
2
|
+
def validate_each record, attribute, value
|
3
|
+
begin
|
4
|
+
unless Object.const_get(value).new.kind_of? options[:superclass]
|
5
|
+
record.errors[attribute] << "does not subclass " + options[:superclass].to_s
|
6
|
+
end
|
7
|
+
rescue NameError
|
8
|
+
# Ignore error if class does not exist.
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module ActsAsExecutor
|
2
|
+
class ExecutableGenerator < Rails::Generators::NamedBase
|
3
|
+
source_root File.expand_path("../templates", __FILE__)
|
4
|
+
|
5
|
+
def models
|
6
|
+
template File.join("executables", "executable.rb"), File.join("app", "executables", file_name + ".rb")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActsAsExecutor
|
2
|
+
class InstallGenerator < Rails::Generators::NamedBase
|
3
|
+
include Rails::Generators::Migration
|
4
|
+
|
5
|
+
source_root File.expand_path("../templates", __FILE__)
|
6
|
+
|
7
|
+
def models
|
8
|
+
template File.join("models", "executor.rb"), File.join("app", "models", file_name + ".rb")
|
9
|
+
template File.join("models", "executor_task.rb"), File.join("app", "models", file_name + "_task.rb")
|
10
|
+
end
|
11
|
+
|
12
|
+
def migration
|
13
|
+
migration_template File.join("migration", "create_executors.rb"), File.join("db", "migrate", "create_" + table_name + ".rb")
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.next_migration_number dirname
|
17
|
+
Time.now.utc.strftime "%Y%m%d%H%M%S"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
File without changes
|
data/lib/generators/{templates → acts_as_executor/install/templates}/models/executor_task.rb
RENAMED
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe ActsAsExecutor::Common::FutureTask do
|
4
|
-
before(:each) { @model = ActsAsExecutor::Common::FutureTask.new
|
4
|
+
before(:each) { @model = ActsAsExecutor::Common::FutureTask.new Executable.make, nil }
|
5
5
|
|
6
6
|
it { @model.should be_a Java::java.util.concurrent.FutureTask }
|
7
7
|
|
@@ -13,12 +13,12 @@ describe ActsAsExecutor::Common::InstanceSupportMethods do
|
|
13
13
|
|
14
14
|
describe "#log_message" do
|
15
15
|
it "should return a string" do
|
16
|
-
@model.send(:log_message, "name", "doing", 1.to_s, "
|
16
|
+
@model.send(:log_message, "name", "doing", 1.to_s, "executable", "message").should == log_message("name", "doing", 1.to_s, "executable", "message")
|
17
17
|
end
|
18
18
|
|
19
19
|
context "when message is a hash" do
|
20
20
|
it "should return a string" do
|
21
|
-
@model.send(:log_message, "name", "doing", 1.to_s, "
|
21
|
+
@model.send(:log_message, "name", "doing", 1.to_s, "executable", {:attribute_one => "attribute_one_value", :attribute_two => "attribute_two_value"}).should == log_message("name", "doing", 1.to_s, "executable", {:attribute_one => "attribute_one_value", :attribute_two => "attribute_two_value"})
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -19,16 +19,16 @@ describe ActsAsExecutor::Executor::Model::InstanceMethods do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
describe "#execute" do
|
22
|
-
before(:each) { @
|
22
|
+
before(:each) { @executable = Executable.make }
|
23
23
|
after(:each) { @model.send(:executor).shutdown }
|
24
24
|
|
25
25
|
it "should execute a task" do
|
26
26
|
@model.send :startup
|
27
27
|
|
28
|
-
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @
|
29
|
-
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @
|
28
|
+
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "for execution (one time)")
|
29
|
+
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @executable.class.name)
|
30
30
|
|
31
|
-
future = @model.send :execute, @
|
31
|
+
future = @model.send :execute, @executable, 1.to_s
|
32
32
|
future.get
|
33
33
|
|
34
34
|
future.is_done.should be_true
|
@@ -38,10 +38,10 @@ describe ActsAsExecutor::Executor::Model::InstanceMethods do
|
|
38
38
|
@model = Executor.make :max_tasks => 1, :schedulable => true
|
39
39
|
@model.send :startup
|
40
40
|
|
41
|
-
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @
|
42
|
-
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @
|
41
|
+
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "for execution (one shot)")
|
42
|
+
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @executable.class.name)
|
43
43
|
|
44
|
-
future = @model.send :execute, @
|
44
|
+
future = @model.send :execute, @executable, 1.to_s, ActsAsExecutor::Task::Schedules::ONE_SHOT, 0, nil, ActsAsExecutor::Common::Units::SECONDS
|
45
45
|
future.get
|
46
46
|
|
47
47
|
future.is_done.should be_true
|
@@ -51,10 +51,10 @@ describe ActsAsExecutor::Executor::Model::InstanceMethods do
|
|
51
51
|
@model = Executor.make :max_tasks => 1, :schedulable => true
|
52
52
|
@model.send :startup
|
53
53
|
|
54
|
-
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @
|
55
|
-
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @
|
54
|
+
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "for execution (fixed delay)")
|
55
|
+
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @executable.class.name)
|
56
56
|
|
57
|
-
future = @model.send :execute, @
|
57
|
+
future = @model.send :execute, @executable, 1.to_s, ActsAsExecutor::Task::Schedules::FIXED_DELAY, 0, 2, ActsAsExecutor::Common::Units::SECONDS
|
58
58
|
|
59
59
|
future.should_not be_nil
|
60
60
|
end
|
@@ -63,10 +63,10 @@ describe ActsAsExecutor::Executor::Model::InstanceMethods do
|
|
63
63
|
@model = Executor.make :max_tasks => 1, :schedulable => true
|
64
64
|
@model.send :startup
|
65
65
|
|
66
|
-
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @
|
67
|
-
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @
|
66
|
+
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "for execution (fixed rate)")
|
67
|
+
@model.send(:log).should_receive(:info).with log_message(@model.name, "enqueued", 1.to_s, @executable.class.name)
|
68
68
|
|
69
|
-
future = @model.send :execute, @
|
69
|
+
future = @model.send :execute, @executable, 1.to_s, ActsAsExecutor::Task::Schedules::FIXED_RATE, 0, 2, ActsAsExecutor::Common::Units::SECONDS
|
70
70
|
|
71
71
|
future.should_not be_nil
|
72
72
|
end
|
@@ -75,11 +75,11 @@ describe ActsAsExecutor::Executor::Model::InstanceMethods do
|
|
75
75
|
it "should log exception" do
|
76
76
|
@model.send :startup
|
77
77
|
|
78
|
-
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @
|
78
|
+
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "for execution (one time)")
|
79
79
|
@model.send(:executor).should_receive(:execute).and_raise Java::java.util.concurrent.RejectedExecutionException.new
|
80
|
-
@model.send(:log).should_receive(:warn).with log_message(@model.name, "preparing", 1.to_s, @
|
80
|
+
@model.send(:log).should_receive(:warn).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "encountered a rejected execution exception")
|
81
81
|
|
82
|
-
@model.send :execute, @
|
82
|
+
@model.send :execute, @executable, 1.to_s
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -88,10 +88,10 @@ describe ActsAsExecutor::Executor::Model::InstanceMethods do
|
|
88
88
|
@model = Executor.make :max_tasks => 1, :schedulable => true
|
89
89
|
@model.send :startup
|
90
90
|
|
91
|
-
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @
|
92
|
-
@model.send(:log).should_receive(:error).with log_message(@model.name, "preparing", 1.to_s, @
|
91
|
+
@model.send(:log).should_receive(:debug).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "for execution (one time)")
|
92
|
+
@model.send(:log).should_receive(:error).with log_message(@model.name, "preparing", 1.to_s, @executable.class.name, "encountered an unexpected exception. java.lang.IllegalArgumentException: No enum const class java.util.concurrent.TimeUnit.RANDOM")
|
93
93
|
|
94
|
-
@model.send :execute, @
|
94
|
+
@model.send :execute, @executable, 1.to_s, nil, nil, nil, "random"
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
data/spec/support/blueprints.rb
CHANGED
@@ -8,13 +8,13 @@ Executor.blueprint do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
ExecutorTask.blueprint do
|
11
|
-
id
|
11
|
+
id { "#{sn}" }
|
12
12
|
executor
|
13
|
-
|
14
|
-
arguments
|
13
|
+
executable { "Executable" }
|
14
|
+
arguments { {:attribute_one => "attribute_one_value", :attribute_two => "attribute_two_value"} }
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
Executable.blueprint do
|
18
18
|
arguments { {:attribute_one => "attribute_one_value", :attribute_two => "attribute_two_value"} }
|
19
19
|
object.stub :execute
|
20
20
|
end
|
data/spec/support/classes.rb
CHANGED
@@ -39,7 +39,7 @@ ActiveRecord::Schema.define do
|
|
39
39
|
|
40
40
|
create_table :executor_tasks, :force => true do |t|
|
41
41
|
t.integer :executor_id
|
42
|
-
t.string :
|
42
|
+
t.string :executable
|
43
43
|
t.string :arguments
|
44
44
|
t.string :schedule
|
45
45
|
t.integer :start
|
@@ -49,7 +49,6 @@ ActiveRecord::Schema.define do
|
|
49
49
|
end
|
50
50
|
ExecutorTask.acts_as_executor_task
|
51
51
|
|
52
|
-
#
|
53
|
-
Object.const_set "
|
54
|
-
|
55
|
-
Clazz.send :include, ActsAsExecutor::Task::Clazz
|
52
|
+
# Executable
|
53
|
+
Object.const_set "Executable", Class.new(ActsAsExecutor::Task::Executable)
|
54
|
+
Executable.send :extend, Machinist::Machinable
|
@@ -20,7 +20,7 @@ def log_statement executor_name, statement
|
|
20
20
|
"\"" + executor_name + "\" " + statement
|
21
21
|
end
|
22
22
|
|
23
|
-
def log_message executor_name, doing, task_id,
|
23
|
+
def log_message executor_name, doing, task_id, executable_name, message = ""
|
24
24
|
if message.kind_of? Hash then message = "with \"" + message.inspect + "\"" end
|
25
|
-
"\"" + executor_name + "\" " + doing + " \"" + task_id + "#" +
|
25
|
+
"\"" + executor_name + "\" " + doing + " \"" + task_id + "#" + executable_name + "\" " + message
|
26
26
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe ActsAsExecutor::Task::
|
4
|
-
before(:each) { @model =
|
3
|
+
describe ActsAsExecutor::Task::Executable do
|
4
|
+
before(:each) { @model = Executable.make }
|
5
5
|
|
6
6
|
it { @model.should be_a Java::java.lang.Runnable }
|
7
7
|
it { @model.should_not allow_public_access_for_methods :run }
|
@@ -6,7 +6,7 @@ describe ActsAsExecutor::Task::Model::InstanceMethods do
|
|
6
6
|
it { @model.should_not allow_public_access_for_methods :enqueue, :instantiate, :cancel, :done_handler, :uncaught_exception_handler }
|
7
7
|
|
8
8
|
describe "#enqueue" do
|
9
|
-
before(:each) { @
|
9
|
+
before(:each) { @executable = Executable.make }
|
10
10
|
|
11
11
|
it "should enqueue task" do
|
12
12
|
@model.send(:future).should be_nil
|
@@ -14,9 +14,9 @@ describe ActsAsExecutor::Task::Model::InstanceMethods do
|
|
14
14
|
future = double "Future"
|
15
15
|
future.stub :done_handler=
|
16
16
|
|
17
|
-
@model.executor.send(:log).should_receive(:debug).with log_message(@model.executor.name, "creating", @model.id.to_s, @model.
|
18
|
-
@model.should_receive(:instantiate).and_return @
|
19
|
-
@model.executor.should_receive(:execute).with(@
|
17
|
+
@model.executor.send(:log).should_receive(:debug).with log_message(@model.executor.name, "creating", @model.id.to_s, @model.executable, @model.arguments)
|
18
|
+
@model.should_receive(:instantiate).and_return @executable
|
19
|
+
@model.executor.should_receive(:execute).with(@executable, @model.id.to_s, @model.schedule, @model.start, @model.every, @model.units).and_return future
|
20
20
|
|
21
21
|
@model.send :enqueue
|
22
22
|
|
@@ -28,7 +28,7 @@ describe ActsAsExecutor::Task::Model::InstanceMethods do
|
|
28
28
|
exception = RuntimeError.new
|
29
29
|
|
30
30
|
@model.should_receive(:instantiate).and_raise exception
|
31
|
-
@model.executor.send(:log).should_receive(:error).with log_message(@model.executor.name, "creating", @model.id.to_s, @model.
|
31
|
+
@model.executor.send(:log).should_receive(:error).with log_message(@model.executor.name, "creating", @model.id.to_s, @model.executable, "encountered an unexpected exception. " + exception.to_s)
|
32
32
|
|
33
33
|
@model.send :enqueue
|
34
34
|
end
|
@@ -37,16 +37,16 @@ describe ActsAsExecutor::Task::Model::InstanceMethods do
|
|
37
37
|
|
38
38
|
describe "#instantiate" do
|
39
39
|
it "should return an instance" do
|
40
|
-
instance = @model.send :instantiate, @model.
|
40
|
+
instance = @model.send :instantiate, @model.executable, @model.arguments
|
41
41
|
|
42
|
-
instance.class.name.should == @model.
|
42
|
+
instance.class.name.should == @model.executable
|
43
43
|
instance.arguments.should == @model.arguments
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
describe "#done_handler" do
|
48
48
|
it "should invoke destroy" do
|
49
|
-
@model.executor.send(:log).should_receive(:debug).with log_message(@model.executor.name, "completed", @model.id.to_s, @model.
|
49
|
+
@model.executor.send(:log).should_receive(:debug).with log_message(@model.executor.name, "completed", @model.id.to_s, @model.executable)
|
50
50
|
@model.should_receive :destroy
|
51
51
|
|
52
52
|
@model.send :done_handler
|
@@ -54,12 +54,12 @@ describe ActsAsExecutor::Task::Model::InstanceMethods do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
describe "#uncaught_exception_handler" do
|
57
|
-
before(:each) { @
|
57
|
+
before(:each) { @executable = Executable.make }
|
58
58
|
|
59
59
|
it "should log exception" do
|
60
60
|
exception = RuntimeError.new
|
61
61
|
|
62
|
-
@model.executor.send(:log).should_receive(:error).with log_message(@model.executor.name, "executing", @model.id.to_s, @model.
|
62
|
+
@model.executor.send(:log).should_receive(:error).with log_message(@model.executor.name, "executing", @model.id.to_s, @model.executable, "encountered an uncaught exception. " + exception.to_s)
|
63
63
|
|
64
64
|
@model.send :uncaught_exception_handler, exception
|
65
65
|
end
|
@@ -8,7 +8,7 @@ describe ClassExistsValidator do
|
|
8
8
|
describe "#validate_each" do
|
9
9
|
context "when class does not exist" do
|
10
10
|
it "should set error message" do
|
11
|
-
attribute = "
|
11
|
+
attribute = "executable"
|
12
12
|
record = double "Record"
|
13
13
|
record.stub(:errors).and_return( { attribute => [] } )
|
14
14
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ClassSubclassesValidator do
|
4
|
+
before(:each) { @model = ClassSubclassesValidator.new Hash[ :attributes => true, :superclass => Comparable ] }
|
5
|
+
|
6
|
+
it { @model.should be_a ActiveModel::EachValidator }
|
7
|
+
|
8
|
+
describe "#validate_each" do
|
9
|
+
context "when class does not subclass" do
|
10
|
+
it "should set error message" do
|
11
|
+
attribute = "executable"
|
12
|
+
record = double "Record"
|
13
|
+
record.stub(:errors).and_return( { attribute => [] } )
|
14
|
+
|
15
|
+
@model.validate_each record, attribute, "Object"
|
16
|
+
|
17
|
+
record.errors[attribute].should include "does not subclass Comparable"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: acts_as_executor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 6
|
5
|
-
version: 1.0.0.
|
5
|
+
version: 1.0.0.rc3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Phil Ostler
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-09-22 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: activemodel
|
@@ -78,6 +77,12 @@ extensions: []
|
|
78
77
|
extra_rdoc_files: []
|
79
78
|
|
80
79
|
files:
|
80
|
+
- .rspec
|
81
|
+
- acts_as_executor.gemspec
|
82
|
+
- Gemfile
|
83
|
+
- LICENSE
|
84
|
+
- Rakefile
|
85
|
+
- README.markdown
|
81
86
|
- lib/acts_as_executor.rb
|
82
87
|
- lib/acts_as_executor/version.rb
|
83
88
|
- lib/acts_as_executor/common/future_task.rb
|
@@ -87,17 +92,19 @@ files:
|
|
87
92
|
- lib/acts_as_executor/executor/model/class_methods.rb
|
88
93
|
- lib/acts_as_executor/executor/model/instance_methods.rb
|
89
94
|
- lib/acts_as_executor/executor/model/instance_support_methods.rb
|
90
|
-
- lib/acts_as_executor/task/
|
95
|
+
- lib/acts_as_executor/task/executable.rb
|
91
96
|
- lib/acts_as_executor/task/schedules.rb
|
92
97
|
- lib/acts_as_executor/task/model/class_methods.rb
|
93
98
|
- lib/acts_as_executor/task/model/instance_methods.rb
|
94
99
|
- lib/acts_as_executor/task/model/instance_support_methods.rb
|
95
100
|
- lib/acts_as_executor/validators/class_exists_validator.rb
|
96
|
-
- lib/acts_as_executor/validators/
|
97
|
-
- lib/generators/
|
98
|
-
- lib/generators/templates/
|
99
|
-
- lib/generators/
|
100
|
-
- lib/generators/templates/
|
101
|
+
- lib/acts_as_executor/validators/class_subclasses_validator.rb
|
102
|
+
- lib/generators/acts_as_executor/executable/executable_generator.rb
|
103
|
+
- lib/generators/acts_as_executor/executable/templates/executables/executable.rb
|
104
|
+
- lib/generators/acts_as_executor/install/install_generator.rb
|
105
|
+
- lib/generators/acts_as_executor/install/templates/migration/create_executors.rb
|
106
|
+
- lib/generators/acts_as_executor/install/templates/models/executor.rb
|
107
|
+
- lib/generators/acts_as_executor/install/templates/models/executor_task.rb
|
101
108
|
- spec/acts_as_executor_spec.rb
|
102
109
|
- spec/spec_helper.rb
|
103
110
|
- spec/common/future_task_spec.rb
|
@@ -111,16 +118,13 @@ files:
|
|
111
118
|
- spec/support/classes.rb
|
112
119
|
- spec/support/custom_matchers.rb
|
113
120
|
- spec/support/database_connection.rb
|
114
|
-
- spec/task/
|
121
|
+
- spec/task/executable_spec.rb
|
115
122
|
- spec/task/schedules_spec.rb
|
116
123
|
- spec/task/model/class_methods_spec.rb
|
117
124
|
- spec/task/model/instance_methods_spec.rb
|
118
125
|
- spec/task/model/instance_support_methods_spec.rb
|
119
126
|
- spec/validators/class_exists_validator_spec.rb
|
120
|
-
- spec/validators/
|
121
|
-
- LICENSE
|
122
|
-
- acts_as_executor.gemspec
|
123
|
-
has_rdoc: true
|
127
|
+
- spec/validators/class_subclasses_validator_spec.rb
|
124
128
|
homepage: https://github.com/philostler/acts_as_executor
|
125
129
|
licenses: []
|
126
130
|
|
@@ -144,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
148
|
requirements: []
|
145
149
|
|
146
150
|
rubyforge_project:
|
147
|
-
rubygems_version: 1.
|
151
|
+
rubygems_version: 1.8.10
|
148
152
|
signing_key:
|
149
153
|
specification_version: 3
|
150
154
|
summary: Java Executor framework integration for Rails
|
@@ -1,10 +0,0 @@
|
|
1
|
-
class ClassIncludesValidator < ActiveModel::EachValidator
|
2
|
-
def validate_each record, attribute, value
|
3
|
-
begin
|
4
|
-
throw TypeError unless Object.const_get(value).new.kind_of? options[:includes]
|
5
|
-
rescue NameError
|
6
|
-
rescue TypeError
|
7
|
-
record.errors[attribute] << "does not include " + options[:includes].to_s
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class ActsAsExecutorGenerator < Rails::Generators::NamedBase
|
2
|
-
include Rails::Generators::Migration
|
3
|
-
|
4
|
-
source_root File.expand_path("../templates", __FILE__)
|
5
|
-
|
6
|
-
def models
|
7
|
-
template File.join("models", "executor.rb"), File.join("app", "models", file_name + ".rb")
|
8
|
-
template File.join("models", "executor_task.rb"), File.join("app", "models", file_name + "_task.rb")
|
9
|
-
end
|
10
|
-
|
11
|
-
def migration
|
12
|
-
migration_template File.join("migration", "create_executors.rb"), File.join("db", "migrate", "create_" + table_name + ".rb")
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.next_migration_number dirname
|
16
|
-
Time.now.utc.strftime "%Y%m%d%H%M%S"
|
17
|
-
end
|
18
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe ClassIncludesValidator do
|
4
|
-
before(:each) { @model = ClassIncludesValidator.new Hash[ :attributes => true, :includes => Comparable ] }
|
5
|
-
|
6
|
-
it { @model.should be_a ActiveModel::EachValidator }
|
7
|
-
|
8
|
-
describe "#validate_each" do
|
9
|
-
context "when class does not include" do
|
10
|
-
it "should set error message" do
|
11
|
-
attribute = "clazz"
|
12
|
-
record = double "Record"
|
13
|
-
record.stub(:errors).and_return( { attribute => [] } )
|
14
|
-
|
15
|
-
@model.validate_each record, attribute, "Object"
|
16
|
-
|
17
|
-
record.errors[attribute].should include "does not include Comparable"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|