zuvor
THIS IS ALPHA, UNSTABLE, WORK IN PROGRESS !
simple and reasonably fast implementation of DAGs (directed acyclic graphs) and sets as building blocks for dynamically finding the optimal execution order of interdependent tasks with nondeterministic execution times
a task will run at the earliest possible point when it can run
- is it any good?
- how do i install it?
- Set-API
- Dag-API
- is it fast?
- is it stable?
- how is it implemented?
- how can i contribute?
- license
why?
i had a list of tasks where some tasks needed to run before other tasks.
for example: A before B
, C before A
, D before B
, ...
i needed a programatic way to run those tasks in the most efficient order.
i built vorrang to model and query the underlying partial order:
zuvor gives to the building blocks to do exactly that.
browser?
vorrang can be used to model
- shutdown orders
- task orders
- class hierarchies
- ancestor relationships
- taxonomies
- partial orders
- event orders
- production chains
- dependency graphs
- ...
no dependencies
first let's model the task order:
only works with strings
var Vorrang = ;var dag =;
then i can find out what i can run immediately:
dag;// => ['C', 'D']
sweet - we can already start tasks C
and D
.
let's assume C
has finished.
vorrang// => ['A']
nice - we can start A
now!
you get the idea...
what can i do with it?
is it stable?
it has a large testsuite!
there are probably bugs.
if you find one i appreciate it if you make an issue.
is it fast?
the current focus is on functionality and correctness rather than performance.
i did not optimize prematurely. i chose the data types carefully. its fast enough for my use case. its probably fast enough for your use case.
if you need something faster and have an idea definitely send me an email or make an issue.
query performance memory usage
it currently uses too much memory
how is it implemented?
here's the code its just x lines
parentschildrenancestorsdescendantsinoutupstreamdownstream
how can i contribute?
if you need a function that is not in the API just make an issue and we can discuss and how to implement it best.
i appreciate it if you open an issue first before
API
run(options)
-> Promise
run will call callback
once for every id in ids
that is not in done
.
call them
options:
ids
anArray
orSet
of ids to runcallback
aFunction
that is called for each id that is not indone
- can return a promise
graph
aGraph
(optional) that models the dependencies/order between theids
done
an optionalSet
(defaultnew Set()
) that contains- ids that are done are added to the set
- can be used to blacklist
ids
- things that are already done are not run
pending
an optionalSet
(defaultnew Set()
) that contains the ids that have been called and have returned a promise that is not yet resolvedids
in this set will not be called. can be used to blacklistids
.
reversed
aBoolean
(optional, defaultfalse
) whether to treat thegraph
(if present) in reverse orderstrict
an optionalBoolean
(defaultfalse
)debug
strict ignore orderings that dont exist
order between some of them
run returns a promise that is resolved when all things have been run
Set
follows the ECMA6 set API where sensible.
new Set(Nothing or Array or Set)
-> Set
create a set: var emptySet = ;// orvar setFromArgs = 1 2 3;// orvar setFromArray = 1 2 3;// orvar clonedSet = setFromArray;
O(n) where n = number of elements in argument array or set
.size
= Integer
number of elements in the set: size; // -> 01 2 3size; // -> 3
O(1)
.values()
or .keys()
-> Array
return an array of all the elements in the set: ; // -> []1 2 3; // -> [1, 2, 3]1 2 3; // -> [1, 2, 3]
O(n) where n = number of elements in the set
.toString()
-> String
return a string representation of the set: ; // -> '#{}'1 2 3; // -> '#{1 2 3}'
O(n) where n = number of elements in the set
.equals(Set or Array)
-> Boolean
return whether two sets contain the same elements: ; // -> true; // -> falsevar set = 1 2 3;set; // -> falseset; // -> trueset; // -> trueset; // -> trueset; // -> false
best case if size differs is O(1). worst case is O(n) where n = number of elements in the set
.has(Value)
-> Boolean
return whether a value is in the set: var set = 1 2 3;set; // -> trueset; // -> false
O(1)
.add(Value or Array or Set)
-> Set
add elements to the set and return set: var set = ;set;// add side effects original set!set; // -> [1]set;set; // -> [1, 2, 3]set;set; // -> [1, 2, 3, 4, 5]set;set; // -> [1, 2, 3, 4, 5, 6, 7]// add can be chainedset;set; // -> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
O(1) for a single value. O(n) for a set (array) where n = number of elements in the set (array)
.delete(Value or Array or Set)
-> Set
delete elements from the set and return set: var set = 1 2 3 4 5 6 7 8 9 10;set;// delete side effects original set!set; // -> [2, 3, 4, 5, 6, 7, 8, 9, 10]set;set; // -> [4, 5, 6, 7, 8, 9, 10]set;set; // -> [6, 7, 8, 9, 10]set;set; // -> [8, 9, 10]// delete can be chainedset;set; // -> []
O(1) for a single value. O(n) for a set (array) where n = number of elements in the set (array)
.clone()
-> Set
return a new set that has the same elements as the set: var set = 1 2 3;var clone = set;set; // -> true
O(n) where n = number of elements in the set
.clear()
-> Set
delete all elements from the set and return set: var set = 1 2 3;setsize; // -> 3setclear;setsize; // -> 0
O(1)
Graph
Value
= String
or Number
new Graph
-> Graph
create a graph: var graph = ;
O(1)
.add(from Value, to Value)
-> Graph
add an edge and return graph: var graph =;
O(1)
a
or path from a
to b
exists: .has(a Value, [b Value])
-> Boolean
return whether node var graph =graph; // -> truegraph; // -> falsegraph; // -> truegraph; // -> false// transitive path: a to c via bgraph; // -> true
whether node exists: O(1)
if direct edge between a and b exists: O(1)
if a transitive path between a and b exists: worst case O(n * m) where n is the number of edges in the path and m is the max number of edges connected to any node in the graph.
.values()
or .keys()
-> Array
return an array of all the nodes in the graph: ; // -> []; // -> ['a', 'b']; // -> ['a', 'b']
O(n) where n = number of nodes in the graph
.edges()
-> Array
return an array of all the edges in the graph: ; // -> []; // -> [['a', 'b']]
O(n) where n = number of edges in the graph
.parentless()
-> Array
return nodes that have no parents (no incoming edges): ; // -> ['a']
O(n) where n = number of nodes in the graph
.childless()
-> Array
return nodes that have no children (no outgoing edges): ; // -> ['b']
O(n) where n = number of nodes in the graph
.whereAllParentsIn(Array or Set)
-> Array
return nodes whose parents are all in array: var graph =graph; // -> ['b', 'c']// nodes in the source array are not in the output arraygraph; // -> ['c']graph; // -> ['d']
worst case: O(n * m) where n = number of elements in the array/set and m = max number of parents of any node in the array/set
.whereAllChildrenIn(Array or Set)
-> Array
return nodes whose children are all in array: var graph =graph; // -> ['c', 'b']// nodes in the source array are not in the output arraygraph; // -> ['c']graph; // -> ['a']
worst case: O(n * m) where n = number of elements in the array/set and m = max number of children of any node in the array/set
license: MIT
TODO
-
handle strictness
- build a scenario where that is a problem
- in graph but not in ids and blockings children that depend on it
-
test edge cases of the run function
-
document run function in readme
-
use zuvor run function from blaze for shutdown
-
finish readme
- read api again
- description
- question sections
- example
-
example.js (taken from integration test)
-
npm publish
-
publish
-
make sure travis is working
uses and includes a set and a graph datatype
where an order exists only for some services
you can use it for
tasks are run as soon as they are ready to run