orchestrated 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +21 -8
- data/Rakefile +3 -0
- data/lib/generators/orchestrated/active_record_generator.rb +17 -0
- data/lib/generators/orchestrated/templates/migration.rb +29 -0
- data/lib/orchestrated/version.rb +1 -1
- data/orchestrated.gemspec +10 -7
- metadata +47 -13
data/README.markdown
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
Orchestrated
|
2
2
|
============
|
3
3
|
|
4
|
-
The [delayed_job](https://github.com/collectiveidea/delayed_job) Ruby Gem provides a job queuing system for Ruby. It implements an elegant API for delaying execution of any object method. Not only is the execution of the method (message delivery) delayed in time, it is potentially shifted in space. By shifting in space, i.e. running in a separate virtual machine, possibly on a separate computer, multiple CPUs can be brought to bear on a computing problem.
|
4
|
+
The [delayed_job](https://github.com/collectiveidea/delayed_job) Ruby Gem provides a job queuing system for Ruby. It implements an elegant API for delaying execution of any object method. Not only is the execution of the method (message delivery) delayed in time, it is potentially shifted in space too. By shifting in space, i.e. running in a separate virtual machine, possibly on a separate computer, multiple CPUs can be brought to bear on a computing problem.
|
5
5
|
|
6
|
-
By breaking up otherwise serial execution into multiple queued jobs, a program can be made more scalable.
|
6
|
+
By breaking up otherwise serial execution into multiple queued jobs, a program can be made more scalable. This sort of distributed queue-processing architecture has a long and successful history in data processing.
|
7
7
|
|
8
|
-
Queuing works well for simple tasks. By simple
|
8
|
+
Queuing works well for simple tasks. By simple we mean, the task can be done all at once, in one piece. It has no dependencies on other tasks. This works well for performing a file upload task in the background (to avoid tying up a Ruby virtual machine process/thread). More complex (compound) multi-part tasks, however, do not fit this model. Examples of complex (compound) tasks include:
|
9
9
|
|
10
10
|
1. pipelined (multi-step) generation of complex PDF documents
|
11
11
|
2. extract/transfer/load (ETL) jobs that may load thousands of database records
|
@@ -27,6 +27,13 @@ Or install it yourself as:
|
|
27
27
|
|
28
28
|
$ gem install orchestrated
|
29
29
|
|
30
|
+
Now generate the database migration:
|
31
|
+
|
32
|
+
$ rails g orchestrated:active_record
|
33
|
+
$ rake db:migrate
|
34
|
+
|
35
|
+
If you do not already have [delayed_job](https://github.com/collectiveidea/delayed_job) set up, you'll need to do that as well.
|
36
|
+
|
30
37
|
The API
|
31
38
|
-------
|
32
39
|
|
@@ -53,14 +60,20 @@ Declaring ```acts_as_orchestrated``` on your class gives it two methods:
|
|
53
60
|
* ```orchestrated```—call this to specify your workflow prerequisite, and designate a workflow step
|
54
61
|
* ```orchestration```—call this in the context of a workflow step (execution) to access orchestration (and prerequisite) context
|
55
62
|
|
56
|
-
After that you can orchestrate any method on such a class
|
63
|
+
After that you can orchestrate any method on such a class. Let's say you needed to download files from a remote system (a slow process), transform each one, and then load it into your system. Imagine you had had a Downloader class that knew how to download and an Xform class that knew how to transform the downloaded file and load it into your system. You might write an orchestration like this:
|
57
64
|
|
58
65
|
```ruby
|
59
|
-
|
60
|
-
|
66
|
+
xform = Xform.new
|
67
|
+
xform.orchestrated(
|
68
|
+
xform.orchestrated(
|
69
|
+
Downloader.new.orchestrated.download(
|
70
|
+
:from=>'http://foo.bar.com/customer_fred', :to=>'fred_file'
|
71
|
+
)
|
72
|
+
).transform('fred_file', 'fred_file_processed')
|
73
|
+
).load('fred_file_processed')
|
61
74
|
```
|
62
75
|
|
63
|
-
The next time you process a delayed job, the :
|
76
|
+
The next time you process a delayed job, the :download message will be delivered to a Downloader. After the download is complete, the next time a delayed job is processed, the :transform message will be delivered to an Xform object.
|
64
77
|
|
65
78
|
What happened there? The pattern is:
|
66
79
|
|
@@ -68,7 +81,7 @@ What happened there? The pattern is:
|
|
68
81
|
2. call orchestrated on it: this returns an "orchestration"
|
69
82
|
3. send a message to the orchestration (returned in the second step)
|
70
83
|
|
71
|
-
Now the messages you can send in (3) are limited to the messages that your object can respond to. The message will be
|
84
|
+
Now the messages you can send in (3) are limited to the messages that your object can respond to. The message will be remembered by the framework and "replayed" (on a new instance of your object) somewhere on the network (later).
|
72
85
|
|
73
86
|
Not accidentally, this is similar to the way [delayed_job](https://github.com/collectiveidea/delayed_job)'s delay method works. Under the covers, orchestrated is conspiring with [delayed_job](https://github.com/collectiveidea/delayed_job) when it comes time to actually execute a workflow step. Before that time though, orchestrated keeps track of everything.
|
74
87
|
|
data/Rakefile
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
# borrowed from delayed_job_active_record, and modified…
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
require 'rails/generators/active_record/migration'
|
4
|
+
|
5
|
+
# Extend the DelayedJobGenerator so that it creates an AR migration
|
6
|
+
module Orchestrated
|
7
|
+
class ActiveRecordGenerator < Rails::Generators::Base
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
extend ActiveRecord::Generators::Migration
|
10
|
+
|
11
|
+
self.source_paths << File.join(File.dirname(__FILE__), 'templates')
|
12
|
+
|
13
|
+
def create_migration_file
|
14
|
+
migration_template 'migration.rb', 'db/migrate/create_orchestrated.rb'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class CreateOrchestrated < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :orchestrations do |table|
|
4
|
+
table.string :state
|
5
|
+
table.text :handler
|
6
|
+
table.references :prerequisite
|
7
|
+
table.references :delayed_job, :polymorphic => true
|
8
|
+
table.timestamps
|
9
|
+
end
|
10
|
+
create_table :completion_expressions do |table|
|
11
|
+
table.string :type
|
12
|
+
# only one kind of completion expression needs this
|
13
|
+
# (OrchestrationCompletion) but I didn't want to put
|
14
|
+
# it in a separate table because it would really contort
|
15
|
+
# the Rails model
|
16
|
+
table.references :orchestration
|
17
|
+
end
|
18
|
+
create_table :composited_completions do |table|
|
19
|
+
table.references :composite_completion
|
20
|
+
table.references :completion_expression
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table :composited_completions
|
26
|
+
drop_table :completion_expressions
|
27
|
+
drop_table :orchestrations
|
28
|
+
end
|
29
|
+
end
|
data/lib/orchestrated/version.rb
CHANGED
data/orchestrated.gemspec
CHANGED
@@ -18,16 +18,19 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
-
gem.add_runtime_dependency 'delayed_job_active_record', '
|
22
|
-
gem.add_runtime_dependency 'activerecord', ['
|
21
|
+
gem.add_runtime_dependency 'delayed_job_active_record', '>= 0.3'
|
22
|
+
gem.add_runtime_dependency 'activerecord', ['~> 3']
|
23
23
|
gem.add_runtime_dependency 'state_machine', ['>= 1']
|
24
24
|
|
25
|
-
gem.add_development_dependency 'rake'
|
26
|
-
gem.add_development_dependency 'rails', ['
|
27
|
-
gem.add_development_dependency 'rspec-rails'
|
25
|
+
gem.add_development_dependency 'rake', ['>= 10']
|
26
|
+
gem.add_development_dependency 'rails', ['~> 3'] # for rspec-rails
|
27
|
+
gem.add_development_dependency 'rspec-rails', ['>= 2.12']
|
28
28
|
# I couldn't get rspecs transactional fixtures setting to do savepoints
|
29
29
|
# in this project (which is not _really_ a Rails app). database_cleaner
|
30
30
|
# claims it'll help us clean up the database so let's try it!
|
31
|
-
gem.add_development_dependency 'database_cleaner'
|
32
|
-
gem.add_development_dependency 'sqlite3'
|
31
|
+
gem.add_development_dependency 'database_cleaner', ['>= 0.9']
|
32
|
+
gem.add_development_dependency 'sqlite3', ['>= 1.3.6']
|
33
|
+
gem.add_development_dependency 'debugger'
|
34
|
+
# The state_machine:draw rake task needs this
|
35
|
+
gem.add_development_dependency 'ruby-graphviz', ['>= 0.9.0']
|
33
36
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orchestrated
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '0.3'
|
22
22
|
type: :runtime
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.3'
|
30
30
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: '3'
|
38
38
|
type: :runtime
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '3'
|
46
46
|
- !ruby/object:Gem::Dependency
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
requirements:
|
67
67
|
- - ! '>='
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
69
|
+
version: '10'
|
70
70
|
type: :development
|
71
71
|
prerelease: false
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -74,13 +74,13 @@ dependencies:
|
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
77
|
+
version: '10'
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
79
|
name: rails
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
81
81
|
none: false
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ~>
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: '3'
|
86
86
|
type: :development
|
@@ -88,7 +88,7 @@ dependencies:
|
|
88
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
89
|
none: false
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '3'
|
94
94
|
- !ruby/object:Gem::Dependency
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - ! '>='
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '
|
101
|
+
version: '2.12'
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,7 +106,7 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
109
|
+
version: '2.12'
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
111
|
name: database_cleaner
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,7 +114,7 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - ! '>='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
117
|
+
version: '0.9'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -122,9 +122,25 @@ dependencies:
|
|
122
122
|
requirements:
|
123
123
|
- - ! '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: '0'
|
125
|
+
version: '0.9'
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: sqlite3
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 1.3.6
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 1.3.6
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: debugger
|
128
144
|
requirement: !ruby/object:Gem::Requirement
|
129
145
|
none: false
|
130
146
|
requirements:
|
@@ -139,6 +155,22 @@ dependencies:
|
|
139
155
|
- - ! '>='
|
140
156
|
- !ruby/object:Gem::Version
|
141
157
|
version: '0'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: ruby-graphviz
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 0.9.0
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.9.0
|
142
174
|
description: a workflow orchestration framework running on delayed_job and active_record
|
143
175
|
email:
|
144
176
|
- bill@paydici.com
|
@@ -152,6 +184,8 @@ files:
|
|
152
184
|
- Orchestrated::Orchestration_state.png
|
153
185
|
- README.markdown
|
154
186
|
- Rakefile
|
187
|
+
- lib/generators/orchestrated/active_record_generator.rb
|
188
|
+
- lib/generators/orchestrated/templates/migration.rb
|
155
189
|
- lib/orchestrated.rb
|
156
190
|
- lib/orchestrated/base.rb
|
157
191
|
- lib/orchestrated/completion.rb
|