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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1db9f251078cde21dde04e7c3c1c39c9ad6507ac
4
- data.tar.gz: '0609f7301f92b48d44f9c7f62d5a5456b927945e'
3
+ metadata.gz: 5601cb9eab89d7222a573523813c5ab64a5beba1
4
+ data.tar.gz: a147ad7182a1e4aa06ce2bfb9de56a50cf573903
5
5
  SHA512:
6
- metadata.gz: 1a849e5637bd3aa31f3cc9f80ebf335ee9691f2d54033bde1ace51b05fa86a4f78abb995ef647e1cb025f0050697bef151421d0530db3c1486d8baaf23df5766
7
- data.tar.gz: eb9d2f5f43b0fa02ff67620f1b4731de57491d70e437e80c9f0f58153d765d7118ba0a6280022846ec903cb02b1c43431ddf1c0b5ddd6f92c8e1d51f0d0c12f6
6
+ metadata.gz: abd107a4109aecdabf779b775e0628c3a92ce6efd87129ecece67b6e672be2296eb3c6a8eeda55cd2e9884c3cbd0e72e34d5f66a23d249d95ea56c787de736c0
7
+ data.tar.gz: 141c79dbda2a86b74fdcbd2cbf25fa993576189b4655bceece1b9f304aac0899e7fd794b2226ac493b0ed31f21b3b95b923c95469e9e8e6f21519172f3e4ad82
@@ -25,3 +25,8 @@ All notable changes to this project will be documented in this file.
25
25
 
26
26
  ### Changed
27
27
  - Re-written specs to use async callback
28
+
29
+ ## [1.1.1] - 05-Jan-2019
30
+
31
+ ### Changed
32
+ - Moved invocation of task executions out of Signal Trap context
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, such as JRuby or Rubinius though it hasn't yet been tested on those.
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
- ## Pre-requisites
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.. in parallel) and will wait until they are both finished before it executes C in a separate process.
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 examples below:
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 first graph would be defined as:
70
+ So the graph above can be defined as:
67
71
 
68
72
  ```
69
73
  my_graph = {
70
- s: [:q, :r, :t],
71
- q: [:r],
72
- r: [],
73
- t: []
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 Q, R and T can only start after task S has finished.
82
- * Task R can only start after Q has finished.
83
- * Tasks T and T have no dependants. No other task need wait for them.
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
  ```
@@ -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
- if status.success?
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'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jongleur
4
- VERSION = '1.1.0'
4
+ VERSION = '1.1.1'
5
5
  end
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.0
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: 2018-12-31 00:00:00.000000000 Z
11
+ date: 2019-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphviz