An amusing diversion into the inner workings of the flow.json file.
Editor tabs are flows.
On each flow are zero or more sequences.
A sequence starts with a node that is wired out-of but not wired into (but in practice only 'event trigger' nodes).
Nodes will be executed in the order of the wiring (simplistic viewpoint).
Inside the flows.json file, components are ordered as:
tabs > subflows(dec) > groups > junctions > configs > nodes
A bit of JSONata can indeed analyse and print out the:
- list of tabs (flows) in order [same as in the editor]
- the configuration nodes (these don't have 'wires' property)
- list of groups and subflows
- generate all the different types of (wired) nodes in use, in alphabetical order, with a list of each tab on which they appear and the count of these nodes on that tab
- a list of all sequences, by tab, showing the node type, id, and name
With this information, it is then easy to select the tab and the sequence in the tab (flow-sequence entry point) and then walk the node path.
I have tested this JSONata on my flows.json and I have checked that the path walk does ignore loops so it should avoid going around for ever. Naturally, with a very large flow file the JSONata may not cope too well with the array sizes in use, but you are welcome to try.
Ignoring the tabs, groups, and configs, all other nodes are 'wired' and I have added a 'file-order-index' so that I can see where the node sits inside flow.json.
The above block of code has three sequence start points, but taking the 'Every Hour' inject node as the main entry point for analysis gives:
[
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->P1 East< (557) [4]->API FCS< (558) [5]->OK?< (561) [6]->API Left< (613) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->P1 East< (557) [4]->API FCS< (558) [5]->OK?< (561) [6]->Dates / Array / Plane< (614) [7]->by plane< (565) [8]->Solar FC Power East< (569) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->P1 East< (557) [4]->API FCS< (558) [5]->OK?< (561) [6]->Dates / Array / Plane< (614) [7]->by plane< (565) [8]->Solar FC Power West< (570) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->P1 East< (557) [4]->API FCS< (558) [5]->debug 329< (623) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->P2 West< (560) [5]->API FCS< (558) [6]->OK?< (561) [7]->API Left< (613) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->P2 West< (560) [5]->API FCS< (558) [6]->OK?< (561) [7]->Dates / Array / Plane< (614) [8]->by plane< (565) [9]->Solar FC Power East< (569) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->P2 West< (560) [5]->API FCS< (558) [6]->OK?< (561) [7]->Dates / Array / Plane< (614) [8]->by plane< (565) [9]->Solar FC Power West< (570) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->P2 West< (560) [5]->API FCS< (558) [6]->debug 329< (623) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->10s< (562) [5]->History Times< (615) [6]->History< (622) [7]->Parse< (616) [8]->Actual energy last hour< (617) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->10s< (562) [5]->History Times< (615) [6]->History< (622) [7]->Parse< (616) [8]->Update SFC (act & fc)< (618) [9]->link out 1< (619) [10]->link in 1< (620) [11]->5s< (568) [12]->< (11) [13]->Analyse Forecast< (567) [14]->FC Estimate Today< (572) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->10s< (562) [5]->History Times< (615) [6]->History< (622) [7]->Parse< (616) [8]->Update SFC (act & fc)< (618) [9]->link out 1< (619) [10]->link in 1< (620) [11]->5s< (568) [12]->< (11) [13]->Analyse Forecast< (567) [14]->FC Estimate Tomorrow< (586) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->10s< (562) [5]->History Times< (615) [6]->History< (622) [7]->Parse< (616) [8]->Update SFC (act & fc)< (618) [9]->link out 1< (619) [10]->link in 1< (620) [11]->5s< (568) [12]->< (11) [13]->HA Graph Array< (566) [14]->FC Solar Table< (571) ",
"[0]->Every Hour< (612) [1]->2 min past< (611) [2]->Site< (556) [3]->10s< (559) [4]->10s< (562) [5]->History Times< (615) [6]->History< (622) [7]->Parse< (616) [8]->Update SFC (act & fc)< (618) [9]->link out 1< (619) [10]->link in 1< (620) [11]->5s< (568) [12]->< (11) [13]->Chart Array< (564) [14]->Forecast< (544) "
]
Which is correct for all possible routing paths given all possible outcomes. [n] is the path step depth, and (x) is the all-wired-nodes in-file index number.
Conclusions:
Flows (the tabs) are ordered by the editor, so moving a tab and deploying re-saves the flow.json with the new order. Hence all important sequences can go in the first tab, and will load first.
All junctions come first, then all wired nodes are saved in the order that they were added to the editor. Hence, if you write a new sequence in order, it will be saved in that order, but if you write it 'backwards' it will be saved in reverse order. Adding a new sequence to a tab will place that sequence order after all other existing sequences on the tab, however it is easy to delete-recreate any other sequence trigger node, thus placing that existing node back at the end of the file (much like 'send to the back' in something like MS PowerPoint). Hence, bringing any one sequence in a flow to the front of the flow-sequence order requires a delete-add action on all other sequence start nodes in that tab.
Sequences must primarily execute in the order of the wiring.
Taking a simple sequence 'Theory' -> A -> B & C -> D - Debug, after A the message is cloned and one goes to B to flow through to D, and the other goes to C, also to flow through to D.
The route-paths show:
[
"[0]->Theory< (366) [1]->A< (348) [2]->B< (349) [3]->Delay-B< (353) [4]->D< (350) [5]->debug 33< (351) ",
"[0]->Theory< (366) [1]->A< (348) [2]->C< (352) [3]->Delay-C< (354) [4]->D< (350) [5]->debug 33< (351) ",
"[0]->Theory< (366) [1]->A< (348) [2]->link out 1< (370) [3]->link in 1< (371) [4]->D< (350) [5]->debug 33< (351) "
]
Ignoring the links (just for testing), there are only two paths. However I understand that node execution is carried out 'round robin' to avoid, in this case, one message going through to the end, followed by the other message.
Hence, all possible node execution sequences are (ignoring the delay nodes):
- Theory > A > B > C > D1 > D2 > debug
- Theory > A > B > C > D2 > D1 > debug
- Theory > A > B > D1 > C > D2 > debug
- Theory > A > C > B > D1 > D2 > debug
- Theory > A > C > B > D2 > D1 > debug
- Theory > A > C > D2 > B > D1 > debug
Although B is (349) in the file, and the first wire connection out of A, I assume that C (352) could be executed before B. When the message is then placed back into the execution queue, it would suggest that if B goes first, C goes before D1 then finally D2. In practice I have only found that message A-B-D always arrives before A-C-D, but these nodes are so simple that the entire flow takes less than 1 ms to execute, and of course the Debug node only pushes the outcome when it is called, so the order of a debug message only indicates the order of the debug node being used, not the order of in-flight node execusion.
And finally, deleting the wiring between A and B/C then re-wiring backwards saves the wire order in reverse, and the flow paths reverse
["[0]->Theory< (366) [1]->A< (348) [2]->C< (352) [3]->Delay-C< (354) [4]->D< (350) [5]->debug 33< (351) ",
"[0]->Theory< (366) [1]->A< (348) [2]->B< (349) [3]->Delay-B< (353) [4]->D< (350) [5]->debug 33< (351) "]
as does the order of execution.
I think it would be indeed possible (but not necessarily desirable or sensible) to select one particular tab(flow), and 'priority' node, and from this auto-edit the flows file to move the enclosing tab forwards, re-order the tab sequence start nodes to promote the sequence, and possibly re-order the node wiring within the sequence.