View Source Cinema.Projection.Rank (cinema v0.1.0)
This module is responsible for ranking a list of projections in a depth-first manner, which can be used to determine the order in which to execute a list of projections, potentially asynchronously.
The derive/2
function is the main entry point, which takes a list of projections and a single
target projection you'd like to run. The function will then proceed to rank all dependencts of the
target projection recursively.
Note that a single dependency can appear multiple times due to being dependents of different subgraphs of the target projection. In this case, the dependency will be ranked multiple times, but the final ranking will be the highest rank of all duplicate dependencies.
Ranked projections can then be grouped by rank, and the groups can be executed in parallel, as they are guaranteed to be independent of each other.
See the depth_first_rank/2
function for more details on how the ranking is actually done.
Summary
Functions
Recursively traverses a list of KV tuples representing a graph of projections and their dependencies, and ranks them in a depth-first manner.
Derives the dependency order of a target projection in a list of projections by ranking them in a depth-first manner.
Functions
Recursively traverses a list of KV tuples representing a graph of projections and their dependencies, and ranks them in a depth-first manner.
Does not do any additional processing on the ranked projections, see derive/2
for that.
Derives the dependency order of a target projection in a list of projections by ranking them in a depth-first manner.
Projections are expected to be given in the form: [{Module.t(), [Module.t()]}]
Note that the order of the returned list is derived simply from the declared hierarchy of the projections, and does not take into account any additional processing that may be required to actually execute the projections. This means that the order of the returned list may not be the optimal order for execution, but it will guarantee that all dependencies are executed before the target projection.
Additionally, the algorithm used is simple in that it "lazily" ranks dependencies after the whole graph has been traversed, and does not attempt to optimize the ranking in any way. A graph could theoretically take into consideration "re-ranking" of dependencies in an attempt to optimize ordering/grouping, but this is not currently implemented.
Also do note that currently this function does not handle cycles in the graph, and will raise an error if a cycle is detected.
See examples:
iex> alias Elixir.Cinema.Projection.Rank
iex> graph = [a: [], b: [], c: [:a, :b], d: [:c], e: [:b], f: [:c, :e]]
iex> Rank.derive!(graph, :d)
[[:a, :b], :c, :d]
iex> Rank.derive!(graph, :e)
[:b, :e]
iex> Rank.derive!(graph, :a)
[:a]
iex> # This isn't neccessarily the optimal order, but it is _correct_.
iex> Rank.derive!(graph, :f)
[[:a, :b], [:c, :e], :f]
# Example with a cycle
iex> alias Elixir.Cinema.Projection.Rank
iex> graph = [a: [:b], b: [:a]]
iex> Rank.derive!(graph, :b)
** (ArgumentError) Projections contain a cycle, cannot derive dependency order.