https://github.com/jamiebuilds/graph-sequencer
Sort items in a graph using a topological sort while resolving cycles with priority groups
https://github.com/jamiebuilds/graph-sequencer
adjacency-lists cycles graph priority-list sequencing sorting
Last synced: 7 months ago
JSON representation
Sort items in a graph using a topological sort while resolving cycles with priority groups
- Host: GitHub
- URL: https://github.com/jamiebuilds/graph-sequencer
- Owner: jamiebuilds
- License: mit
- Created: 2017-12-05T07:59:01.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2020-09-04T01:07:36.000Z (about 5 years ago)
- Last Synced: 2025-03-12T21:02:44.791Z (7 months ago)
- Topics: adjacency-lists, cycles, graph, priority-list, sequencing, sorting
- Language: JavaScript
- Size: 107 KB
- Stars: 28
- Watchers: 2
- Forks: 6
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# graph-sequencer
> Sort items in a graph using a topological sort while resolving cycles with
> priority groups.Say you have some sort of graph of dependencies: (using an adjacency list)
```js
let graph = new Map([
["task-a", ["task-d"]], // task-a depends on task-d
["task-b", ["task-d", "task-a"]],
["task-c", ["task-d"]],
["task-d", ["task-a"]],
]);
```You could run a topological sort on these items, but you'd still end up with
cycles:```
task-a -> task-d -> task-a
```To resolve this you pass "priority groups" to `graph-sequencer`:
```js
let groups = [
["task-d"], // higher priority
["task-a", "task-b", "task-c"], // lower priority
];
```The result will be a chunked list of items sorted topologically and by the
priority groups:```js
let chunks = [
["task-d"],
["task-a", "task-c"],
["task-b"]
];
```You can then run all these items in order with maximum concurrency:
```js
for (let chunk of chunks) {
await Promise.all(chunk.map(task => exec(task)));
}
```However, even with priority groups you can still accidentally create cycles of
dependencies in your graph.`graph-sequencer` will return a list of the unresolved cycles:
```js
let cycles = [
["task-a", "task-b"] // task-a depends on task-b which depends on task-a
];
```However, `graph-sequencer` will still return an "unsafe" set of chunks. When it
comes across a cycle, it will add another chunk with the item with the fewest
dependencies remaining which will often break cycles.All together that looks like this:
```js
const graphSequencer = require('graph-sequencer');graphSequencer({
graph: new Map([
["task-a", ["task-d"]], // task-a depends on task-d
["task-b", ["task-d", "task-a"]],
["task-c", ["task-d"]],
["task-d", ["task-a"]],
]);
groups: [
["task-d"], // higher priority
["task-a", "task-b", "task-c"], // lower priority
],
})
// {
// safe: true,
// chunks: [["task-d"], ["task-a", "task-c"], ["task-b"]],
// cycles: [],
// }
```