acts_as_executor 1.0.0.beta1 → 1.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +30 -13
- data/acts_as_executor.gemspec +17 -0
- data/lib/acts_as_executor.rb +11 -0
- data/lib/acts_as_executor/common/future_task.rb +11 -0
- data/lib/acts_as_executor/executor/factory.rb +13 -0
- data/lib/acts_as_executor/executor/kinds.rb +6 -2
- data/lib/acts_as_executor/executor/model/actions.rb +44 -52
- data/lib/acts_as_executor/executor/model/helpers.rb +14 -0
- data/lib/acts_as_executor/task/model/actions.rb +23 -0
- data/lib/acts_as_executor/task/model/attributes.rb +16 -0
- data/lib/acts_as_executor/task/model/base.rb +3 -1
- data/lib/acts_as_executor/task/model/helpers.rb +14 -0
- data/lib/acts_as_executor/version.rb +1 -1
- data/lib/generators/executor_generator.rb +4 -0
- data/lib/generators/templates/initializer/acts_as_executor.rb +4 -0
- data/spec/spec_helper.rb +0 -0
- metadata +8 -2
data/README.rdoc
CHANGED
@@ -2,13 +2,15 @@
|
|
2
2
|
acts_as_executor seamlessly integrates Java's Executor framework with JRuby on Rails, giving an application the ability to interact with executors in a familiar Rails'eque way.
|
3
3
|
|
4
4
|
==Features
|
5
|
-
* Database persisted,
|
5
|
+
* Database persisted, executor and task configurations
|
6
|
+
* Create and delete both executors and tasks dynamically at runtime
|
7
|
+
* Automatic management of completed tasks
|
6
8
|
|
7
9
|
==Getting Started
|
8
10
|
Rails 3 Gemfile
|
9
11
|
gem "acts_as_executor"
|
10
12
|
Install via
|
11
|
-
gem install acts_as_executor
|
13
|
+
gem install acts_as_executor --pre
|
12
14
|
# or
|
13
15
|
bundle install
|
14
16
|
|
@@ -17,21 +19,31 @@ Install via
|
|
17
19
|
|
18
20
|
e.g.
|
19
21
|
rails generate executor Executor
|
22
|
+
create config/initializers/acts_as_executor.rb
|
20
23
|
create app/models/executor.rb
|
21
24
|
create app/models/executor_task.rb
|
22
|
-
create db/migrate/
|
25
|
+
create db/migrate/20110601230311_create_executors.rb
|
23
26
|
rake db:migrate
|
24
27
|
|
25
|
-
====
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
====Create Executor
|
29
|
+
Executor.create(:name => "cached_executor",
|
30
|
+
:kind => ActsAsExecutor::Executor::Kinds::CACHED)
|
31
|
+
====Create Scheduled Executor
|
32
|
+
Executor.create(:name => "scheduled_executor",
|
33
|
+
:kind => ActsAsExecutor::Executor::Kinds::SCHEDULED,
|
34
|
+
:size => 3)
|
35
|
+
====Create Task
|
36
|
+
e = Executor.find_by_name("cached_executor")
|
29
37
|
e.tasks.create(:clazz => "HelloWorldTask",
|
30
|
-
:arguments => { :message => "This is my
|
38
|
+
:arguments => { :message => "This is my message")
|
39
|
+
====Create Scheduled Task
|
40
|
+
e = Executor.find_by_name("scheduled_executor")
|
41
|
+
e.tasks.create(:clazz => "HelloWorldTask",
|
42
|
+
:arguments => { :message => "This is my scheduled message" },
|
31
43
|
:schedule => ActsAsExecutor::Task::Schedules::FIXED_DELAY,
|
32
44
|
:start => 1,
|
33
45
|
:every => 5,
|
34
|
-
:units => ActsAsExecutor::Common::Units::
|
46
|
+
:units => ActsAsExecutor::Common::Units::MINUTES)
|
35
47
|
|
36
48
|
====Example Task
|
37
49
|
class HelloWorldTask
|
@@ -44,7 +56,12 @@ Install via
|
|
44
56
|
end
|
45
57
|
end
|
46
58
|
|
47
|
-
==
|
48
|
-
|
49
|
-
|
50
|
-
|
59
|
+
==Notes
|
60
|
+
Upon a task completing its execution on a non-scheduled executor, the task will be delete from the database. Due to the possiblity that multiple threads may be attempting to delete records simultaneously, it is recommended NOT to use SQLite as a database provider. In this scenario, database locking may occur causing records to fail deletion and thus exist for tasks that have actually completed thier execution.
|
61
|
+
|
62
|
+
==What's New in Release 1.0.0.beta2
|
63
|
+
* Support for all executor types, scheduled and non-scheduled
|
64
|
+
* Executors can be created and deleted at runtime
|
65
|
+
* Tasks can be created and added to executors at runtime
|
66
|
+
* Automatic management of completed tasks on non-scheduled executors
|
67
|
+
* Custom logger can now be set via initializer
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "acts_as_executor/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "acts_as_executor"
|
7
|
+
s.version = ActsAsExecutor::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Phil Ostler"]
|
10
|
+
s.email = ["philostler@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/philostler/acts_as_executor"
|
12
|
+
s.summary = %q{Java Executor framework integration for Rails}
|
13
|
+
s.description = %q{Seamless integration of Java's Executor framework with JRuby on Rails}
|
14
|
+
|
15
|
+
s.files = Dir["**/*.rb"] + Dir["*.rdoc"] + Dir["LICENSE"] + Dir["*.gemspec"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
end
|
data/lib/acts_as_executor.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "acts_as_executor/common/future_task"
|
1
2
|
require "acts_as_executor/common/units"
|
2
3
|
|
3
4
|
require "acts_as_executor/executor/factory"
|
@@ -14,7 +15,9 @@ require "acts_as_executor/task/schedules"
|
|
14
15
|
|
15
16
|
require "acts_as_executor/task/model/actions"
|
16
17
|
require "acts_as_executor/task/model/associations"
|
18
|
+
require "acts_as_executor/task/model/attributes"
|
17
19
|
require "acts_as_executor/task/model/base"
|
20
|
+
require "acts_as_executor/task/model/helpers"
|
18
21
|
require "acts_as_executor/task/model/validations"
|
19
22
|
|
20
23
|
require "acts_as_executor/validators/class_exists_validator"
|
@@ -29,6 +32,14 @@ module ActsAsExecutor
|
|
29
32
|
def self.logger
|
30
33
|
@@logger ||= Rails.logger
|
31
34
|
end
|
35
|
+
def self.logger= logger
|
36
|
+
@@logger = logger
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.configure
|
40
|
+
yield self
|
41
|
+
end
|
42
|
+
|
32
43
|
def self.rails_startup?
|
33
44
|
File.basename($0) == "rails"
|
34
45
|
end
|
@@ -3,12 +3,25 @@ module ActsAsExecutor
|
|
3
3
|
class Factory
|
4
4
|
def self.create kind, size = nil
|
5
5
|
case kind
|
6
|
+
when ActsAsExecutor::Executor::Kinds::CACHED
|
7
|
+
return Java::java.util.concurrent.Executors.new_cached_thread_pool
|
8
|
+
|
9
|
+
when ActsAsExecutor::Executor::Kinds::FIXED
|
10
|
+
raise TypeError, "size cannot be nil" unless size
|
11
|
+
raise ArgumentError, "size must be larger than 0" unless size.to_i > 0
|
12
|
+
return Java::java.util.concurrent.Executors.new_fixed_thread_pool size.to_i
|
13
|
+
|
14
|
+
when ActsAsExecutor::Executor::Kinds::SINGLE
|
15
|
+
return Java::java.util.concurrent.Executors.new_single_thread_executor
|
16
|
+
|
6
17
|
when ActsAsExecutor::Executor::Kinds::SCHEDULED
|
7
18
|
raise TypeError, "size cannot be nil" unless size
|
8
19
|
raise ArgumentError, "size must be larger than 0" unless size.to_i > 0
|
9
20
|
return Java::java.util.concurrent.Executors.new_scheduled_thread_pool size.to_i
|
21
|
+
|
10
22
|
when ActsAsExecutor::Executor::Kinds::SINGLE_SCHEDULED
|
11
23
|
return Java::java.util.concurrent.Executors.new_single_thread_scheduled_executor
|
24
|
+
|
12
25
|
else
|
13
26
|
return nil
|
14
27
|
end
|
@@ -1,12 +1,16 @@
|
|
1
1
|
module ActsAsExecutor
|
2
2
|
module Executor
|
3
3
|
class Kinds
|
4
|
+
CACHED = "cached"
|
5
|
+
FIXED = "fixed"
|
6
|
+
SINGLE = "single"
|
7
|
+
|
4
8
|
SCHEDULED = "scheduled"
|
5
9
|
SINGLE_SCHEDULED = "single_scheduled"
|
6
10
|
|
7
|
-
ALL = [ SCHEDULED, SINGLE_SCHEDULED ]
|
11
|
+
ALL = [ CACHED, FIXED, SINGLE, SCHEDULED, SINGLE_SCHEDULED ]
|
8
12
|
ALL_SCHEDULED = [ SCHEDULED, SINGLE_SCHEDULED ]
|
9
|
-
REQUIRING_SIZE = [ SCHEDULED ]
|
13
|
+
REQUIRING_SIZE = [ FIXED, SCHEDULED ]
|
10
14
|
end
|
11
15
|
end
|
12
16
|
end
|
@@ -3,68 +3,60 @@ module ActsAsExecutor
|
|
3
3
|
module Model
|
4
4
|
module Actions
|
5
5
|
def self.included base
|
6
|
-
base.after_find :startup, :if =>
|
7
|
-
base.
|
6
|
+
base.after_find :startup, :if => :startup_now?
|
7
|
+
base.after_save :startup, :if => :startup_now?
|
8
|
+
|
9
|
+
base.after_destroy :shutdown, :if => :shutdown_now?
|
8
10
|
end
|
9
|
-
|
11
|
+
|
10
12
|
def startup
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
ActsAsExecutor.log.info "Executor \"" + name + "\" has completed startup"
|
15
|
-
|
16
|
-
ActsAsExecutor.log.debug "Executor \"" + name + "\" attaching tasks..."
|
17
|
-
tasks.each do |t|
|
18
|
-
submit t
|
19
|
-
end
|
20
|
-
ActsAsExecutor.log.info "Executor \"" + name + "\" has completed attaching tasks"
|
21
|
-
end
|
22
|
-
end
|
13
|
+
ActsAsExecutor.log.debug "Executor \"" + name + "\" starting up..."
|
14
|
+
self.executor = ActsAsExecutor::Executor::Factory.create kind, size
|
15
|
+
ActsAsExecutor.log.info "Executor \"" + name + "\" has completed startup"
|
23
16
|
|
24
|
-
|
25
|
-
if self.executor
|
26
|
-
ActsAsExecutor.log.debug "Executor \"" + name + "\" shutting down..."
|
27
|
-
begin
|
28
|
-
self.executor.shutdown
|
29
|
-
rescue Java::java.lang.RuntimePermission
|
30
|
-
ActsAsExecutor.log.error "Executor \"" + name + "\" has experienced a RuntimePermission error"
|
31
|
-
rescue Java::java.lang.SecurityException
|
32
|
-
ActsAsExecutor.log.error "Executor \"" + name + "\" has experienced a SecurityException error"
|
33
|
-
end
|
34
|
-
ActsAsExecutor.log.info "Executor \"" + name + "\" has completed shutdown"
|
35
|
-
end
|
17
|
+
tasks.all
|
36
18
|
end
|
37
19
|
|
38
|
-
def
|
20
|
+
def shutdown
|
21
|
+
ActsAsExecutor.log.debug "Executor \"" + name + "\" shutting down..."
|
39
22
|
begin
|
40
|
-
|
41
|
-
rescue
|
42
|
-
ActsAsExecutor.log.error "Executor \"" + name + "\"
|
43
|
-
|
44
|
-
|
45
|
-
if task.arguments
|
46
|
-
task.arguments.each_pair do |k, v|
|
47
|
-
attribute = "#{k}="
|
48
|
-
clazz.send attribute, v if clazz.respond_to? attribute
|
49
|
-
end
|
23
|
+
self.executor.shutdown
|
24
|
+
rescue Java::java.lang.RuntimePermission
|
25
|
+
ActsAsExecutor.log.error "Executor \"" + name + "\" has experienced a RuntimePermission error"
|
26
|
+
rescue Java::java.lang.SecurityException
|
27
|
+
ActsAsExecutor.log.error "Executor \"" + name + "\" has experienced a SecurityException error"
|
50
28
|
end
|
29
|
+
ActsAsExecutor.log.info "Executor \"" + name + "\" has completed shutdown"
|
30
|
+
end
|
51
31
|
|
32
|
+
def execute clazz, schedule, start, every, units
|
52
33
|
begin
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
34
|
+
if schedulable?
|
35
|
+
units = Java::java.util.concurrent.TimeUnit.value_of(units.upcase)
|
36
|
+
case schedule
|
37
|
+
when ActsAsExecutor::Task::Schedules::ONE_SHOT
|
38
|
+
future = self.executor.schedule clazz, start, units
|
39
|
+
when ActsAsExecutor::Task::Schedules::FIXED_DELAY
|
40
|
+
future = self.executor.schedule_with_fixed_delay clazz, start, every, units
|
41
|
+
when ActsAsExecutor::Task::Schedules::FIXED_RATE
|
42
|
+
future = self.executor.schedule_at_fixed_rate clazz, start, every, units
|
43
|
+
end
|
44
|
+
else
|
45
|
+
case clazz
|
46
|
+
when Java::java.util.concurrent.Callable
|
47
|
+
future = ActsAsExecutor::Common::FutureTask.new clazz
|
48
|
+
when Java::java.lang.Runnable
|
49
|
+
future = ActsAsExecutor::Common::FutureTask.new clazz, nil
|
50
|
+
end
|
51
|
+
self.executor.execute future
|
61
52
|
end
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
53
|
+
return future
|
54
|
+
rescue Java::java.lang.NullPointerException => e
|
55
|
+
ActsAsExecutor.log.error "Executor \"" + name + "\" attaching task threw a NullPointerException. " + e.to_s
|
56
|
+
rescue Java::java.lang.IllegalArgumentException => e
|
57
|
+
ActsAsExecutor.log.error "Executor \"" + name + "\" attaching task threw a IllegalArgumentException. " + e.to_s
|
58
|
+
rescue Java::java.util.concurrent.RejectedExecutionException => e
|
59
|
+
ActsAsExecutor.log.error "Executor \"" + name + "\" attaching task threw a RejectedExecutionException. " + e.to_s
|
68
60
|
end
|
69
61
|
end
|
70
62
|
end
|
@@ -2,6 +2,20 @@ module ActsAsExecutor
|
|
2
2
|
module Executor
|
3
3
|
module Model
|
4
4
|
module Helpers
|
5
|
+
def startup_now?
|
6
|
+
if self.executor == nil && ActsAsExecutor.rails_startup?
|
7
|
+
return true
|
8
|
+
end
|
9
|
+
return false
|
10
|
+
end
|
11
|
+
|
12
|
+
def shutdown_now?
|
13
|
+
if self.executor != nill && ActsAsExecutor.rails_startup?
|
14
|
+
return true
|
15
|
+
end
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
|
5
19
|
def schedulable?
|
6
20
|
ActsAsExecutor::Executor::Kinds::ALL_SCHEDULED.include? kind
|
7
21
|
end
|
@@ -4,6 +4,29 @@ module ActsAsExecutor
|
|
4
4
|
module Actions
|
5
5
|
def self.included base
|
6
6
|
base.serialize :arguments, Hash
|
7
|
+
|
8
|
+
base.after_find :execute, :if => :execute_now?
|
9
|
+
base.after_save :execute, :if => :execute_now?
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
begin
|
14
|
+
instance = clazz.constantize.new
|
15
|
+
rescue NameError
|
16
|
+
ActsAsExecutor.log.error "Task creating task could not create class"
|
17
|
+
end
|
18
|
+
|
19
|
+
if arguments
|
20
|
+
arguments.each_pair do |k, v|
|
21
|
+
attribute = "#{k}="
|
22
|
+
instance.send attribute, v if instance.respond_to? attribute
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
self.future = executor.execute instance, schedule, start, every, units
|
27
|
+
if !executor.schedulable?
|
28
|
+
self.future.task = self
|
29
|
+
end
|
7
30
|
end
|
8
31
|
end
|
9
32
|
end
|
@@ -3,8 +3,10 @@ module ActsAsExecutor
|
|
3
3
|
module Model
|
4
4
|
module Base
|
5
5
|
def acts_as_executor_task
|
6
|
-
send :include, ActsAsExecutor::Task::Model::Associations
|
7
6
|
send :include, ActsAsExecutor::Task::Model::Actions
|
7
|
+
send :include, ActsAsExecutor::Task::Model::Associations
|
8
|
+
send :include, ActsAsExecutor::Task::Model::Attributes
|
9
|
+
send :include, ActsAsExecutor::Task::Model::Helpers
|
8
10
|
send :include, ActsAsExecutor::Task::Model::Validations
|
9
11
|
end
|
10
12
|
end
|
@@ -3,6 +3,10 @@ class ExecutorGenerator < Rails::Generators::NamedBase
|
|
3
3
|
|
4
4
|
source_root File.expand_path("../templates", __FILE__)
|
5
5
|
|
6
|
+
def initializer
|
7
|
+
template File.join("initializer", "acts_as_executor.rb"), File.join("config", "initializers", "acts_as_executor.rb")
|
8
|
+
end
|
9
|
+
|
6
10
|
def models
|
7
11
|
template File.join("models", "executor.rb"), File.join("app", "models", file_name + ".rb")
|
8
12
|
template File.join("models", "executor_task.rb"), File.join("app", "models", file_name + "_task.rb")
|
data/spec/spec_helper.rb
ADDED
File without changes
|
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.beta2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Phil Ostler
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05
|
13
|
+
date: 2011-06-05 00:00:00 +01:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -26,6 +26,7 @@ extra_rdoc_files: []
|
|
26
26
|
files:
|
27
27
|
- lib/acts_as_executor.rb
|
28
28
|
- lib/acts_as_executor/version.rb
|
29
|
+
- lib/acts_as_executor/common/future_task.rb
|
29
30
|
- lib/acts_as_executor/common/units.rb
|
30
31
|
- lib/acts_as_executor/executor/factory.rb
|
31
32
|
- lib/acts_as_executor/executor/kinds.rb
|
@@ -38,15 +39,20 @@ files:
|
|
38
39
|
- lib/acts_as_executor/task/schedules.rb
|
39
40
|
- lib/acts_as_executor/task/model/actions.rb
|
40
41
|
- lib/acts_as_executor/task/model/associations.rb
|
42
|
+
- lib/acts_as_executor/task/model/attributes.rb
|
41
43
|
- lib/acts_as_executor/task/model/base.rb
|
44
|
+
- lib/acts_as_executor/task/model/helpers.rb
|
42
45
|
- lib/acts_as_executor/task/model/validations.rb
|
43
46
|
- lib/acts_as_executor/validators/class_exists_validator.rb
|
44
47
|
- lib/generators/executor_generator.rb
|
48
|
+
- lib/generators/templates/initializer/acts_as_executor.rb
|
45
49
|
- lib/generators/templates/migration/create_executors.rb
|
46
50
|
- lib/generators/templates/models/executor.rb
|
47
51
|
- lib/generators/templates/models/executor_task.rb
|
52
|
+
- spec/spec_helper.rb
|
48
53
|
- README.rdoc
|
49
54
|
- LICENSE
|
55
|
+
- acts_as_executor.gemspec
|
50
56
|
has_rdoc: true
|
51
57
|
homepage: https://github.com/philostler/acts_as_executor
|
52
58
|
licenses: []
|