jongleur 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +23 -15
- data/lib/jongleur/api.rb +14 -7
- data/lib/jongleur/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5601cb9eab89d7222a573523813c5ab64a5beba1
|
4
|
+
data.tar.gz: a147ad7182a1e4aa06ce2bfb9de56a50cf573903
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abd107a4109aecdabf779b775e0628c3a92ce6efd87129ecece67b6e672be2296eb3c6a8eeda55cd2e9884c3cbd0e72e34d5f66a23d249d95ea56c787de736c0
|
7
|
+
data.tar.gz: 141c79dbda2a86b74fdcbd2cbf25fa993576189b4655bceece1b9f304aac0899e7fd794b2226ac493b0ed31f21b3b95b923c95469e9e8e6f21519172f3e4ad82
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -12,9 +12,9 @@ Jongleur is particularly useful for implementing workflows modelled as a [DAG](h
|
|
12
12
|
This gem has been built using the [POSIX/UNIX process model](https://support.sas.com/documentation/onlinedoc/sasc/doc750/html/lr2/zid-6574.htm).
|
13
13
|
It will work on Linux and Mac OS but not on Windows.
|
14
14
|
|
15
|
-
Jongleur has been tested with MRuby 2.4.3, 2.4.4, 2.5.0 and 2.5.1. I would also expect it to work with other Ruby implementations too,
|
15
|
+
Jongleur has been tested with MRuby 2.4.3, 2.4.4, 2.5.0 and 2.5.1. I would also expect it to work with other Ruby implementations too, though it hasn't yet been tested on those.
|
16
16
|
|
17
|
-
##
|
17
|
+
## Depndencies
|
18
18
|
|
19
19
|
This gem depends on the [Graphviz](https://www.graphviz.org/) package for drawing graphs. If this isn't already installed on your system please install with
|
20
20
|
|
@@ -45,32 +45,41 @@ In either case, call `require jongleur` before using the gem.
|
|
45
45
|
|
46
46
|
## What does it do?
|
47
47
|
|
48
|
-
In a nutshell, Jongleur keeps track of a number of tasks and executes them as separate OS processes according to their precedence criteria. For instance, if there are 3 tasks A, B and C, and task C depends on A and B, Jongleur will start executing A and B in separate processes (i.e
|
48
|
+
In a nutshell, Jongleur keeps track of a number of tasks and executes them as separate OS processes according to their precedence criteria. For instance, if there are 3 tasks A, B and C, and task C depends on A and B, Jongleur will start executing A and B in separate processes (i.e. in parallel) and will wait until they are both finished before it executes C in a separate process.
|
49
49
|
|
50
50
|
Jongleur is ideal for running workflows represented as DAGs, but is also useful for simply running tasks in parallel or for whenever you need some multi-processing capability.
|
51
51
|
|
52
52
|
## Concepts
|
53
53
|
|
54
|
+
### Directed Acyclic Graph (DAG)
|
55
|
+
A graph that is directed and without cycles connecting the other edges. DAGs are very useful for representing different kinds of information models, such as task scheduling and business process workflows.
|
56
|
+
|
54
57
|
### Task Graph
|
55
58
|
|
56
59
|
To run Jongleur, you will need to define the tasks to run and their precedence. A _Task Graph_ is a
|
57
|
-
representation of the tasks to be run by Jongleur and it usually (but not exclusively) represents a DAG, as in the
|
60
|
+
representation of the tasks to be run by Jongleur and it usually (but not exclusively) represents a DAG, as in the example below:
|
61
|
+
|
62
|
+
![DAG example](https://upload.wikimedia.org/wikipedia/commons/6/61/Polytree.svg)
|
58
63
|
|
59
|
-
![DAG examples](https://upload.wikimedia.org/wikipedia/commons/f/fa/Dag_graf.JPG)
|
60
64
|
|
61
65
|
A _Task Graph_ is defined as a Hash in the following format:
|
62
66
|
|
63
67
|
`{task-name => list[names-of-dependent-tasks]}`
|
64
68
|
|
65
69
|
|
66
|
-
So the
|
70
|
+
So the graph above can be defined as:
|
67
71
|
|
68
72
|
```
|
69
73
|
my_graph = {
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
+
A: [:C, :D],
|
75
|
+
B: [:D, :E],
|
76
|
+
D: [:F, :G],
|
77
|
+
E: [],
|
78
|
+
C: [],
|
79
|
+
G: [:I],
|
80
|
+
H: [:I],
|
81
|
+
F: [],
|
82
|
+
I: []
|
74
83
|
}
|
75
84
|
|
76
85
|
```
|
@@ -78,12 +87,11 @@ my_graph = {
|
|
78
87
|
where they Hash key is the class name of a Task and the Hash value is an Array of other Tasks that can be
|
79
88
|
run only after this Task is finished. So in the above example:
|
80
89
|
|
81
|
-
* Tasks
|
82
|
-
* Task
|
83
|
-
* Tasks
|
84
|
-
|
85
|
-
__N.B:__ Since the _Task Graph_ is a Hash, any duplicate key entries will be overridden. For instance, if this Task Graph
|
90
|
+
* Tasks C and D can only start after task A has finished.
|
91
|
+
* Task I can only start after G and H have finished.
|
92
|
+
* Tasks C, E, F and I have no dependants. No other tasks need wait for them.
|
86
93
|
|
94
|
+
__N.B:__ Since the _Task Graph_ is a Hash, any duplicate key entries will be overridden. For instance:
|
87
95
|
```
|
88
96
|
my_task_graph = { A: [:B, :C], B: [:D] }
|
89
97
|
```
|
data/lib/jongleur/api.rb
CHANGED
@@ -131,6 +131,7 @@ module Jongleur
|
|
131
131
|
|
132
132
|
Implementation.process_message 'Starting workflow...'
|
133
133
|
trap_quit_signals
|
134
|
+
@finished_tasks_queue = []
|
134
135
|
start_processes
|
135
136
|
|
136
137
|
trap(:CHLD) do
|
@@ -146,6 +147,7 @@ module Jongleur
|
|
146
147
|
t.success_status = status.success?
|
147
148
|
t.finish_time = finish_time
|
148
149
|
dead_task_name = t.name
|
150
|
+
@finished_tasks_queue << { name: dead_task_name, done: status.success?, pid: dead_pid}
|
149
151
|
end
|
150
152
|
msg = "finished task: %s, process: %i, exit_status: %i, success: %s"
|
151
153
|
Implementation.process_message msg % [dead_task_name,
|
@@ -153,12 +155,7 @@ module Jongleur
|
|
153
155
|
status.exitstatus,
|
154
156
|
status.success?]
|
155
157
|
|
156
|
-
|
157
|
-
Implementation.run_descendants(dead_task_name)
|
158
|
-
else
|
159
|
-
msg = "Task #{dead_task_name} with process id #{dead_pid} was not succesfully completed."
|
160
|
-
Implementation.process_message(msg)
|
161
|
-
end
|
158
|
+
|
162
159
|
end
|
163
160
|
|
164
161
|
# it's possible for the last CHLD signal to arrive after our trap
|
@@ -167,9 +164,19 @@ module Jongleur
|
|
167
164
|
# the oncoming exception so we don't get a crash.
|
168
165
|
rescue Errno::ECHILD
|
169
166
|
end
|
170
|
-
end
|
167
|
+
end #trap
|
171
168
|
|
172
169
|
loop do
|
170
|
+
# run task's descendants as soon as task appears on 'finished' queue
|
171
|
+
while task = @finished_tasks_queue.pop
|
172
|
+
if task[:done]
|
173
|
+
Implementation.run_descendants(task[:name])
|
174
|
+
else
|
175
|
+
msg = "Task #{task[:name]} with process id #{task[:pid]} was not succesfully completed."
|
176
|
+
Implementation.process_message(msg)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
173
180
|
# We exit once all the child processes and their descendants are accounted for
|
174
181
|
if Implementation.running_tasks.empty?
|
175
182
|
Implementation.process_message 'Workflow finished'
|
data/lib/jongleur/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jongleur
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fred Heath
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphviz
|