|
1 | 1 | from graphviz import Digraph |
2 | 2 |
|
| 3 | +BACKUP_COLOR = '#888888' |
| 4 | + |
3 | 5 | # Initialize the Digraph |
4 | 6 | dot = Digraph( |
5 | 7 | comment='Workflow Diagram', |
|
10 | 12 | 'fillcolor': 'lightgrey', |
11 | 13 | 'fontname': 'Helvetica' |
12 | 14 | }, |
13 | | - edge_attr={'color': 'black'} |
| 15 | + edge_attr={'color': 'black', 'fontname': 'Helvetica-Narrow', 'fontsize': '10'} |
14 | 16 | ) |
15 | 17 |
|
16 | 18 | # NON-ZIP NODES |
17 | 19 | dot.node('START', 'START', shape='ellipse', fillcolor='black', fontcolor='white') |
18 | 20 | dot.node('END', 'END', shape='ellipse', fillcolor='#77DD77') |
| 21 | +dot.node('SKIP1', 'SKIP', shape='ellipse', fillcolor='#77DD77') |
| 22 | +dot.node('SKIP2', 'SKIP', shape='ellipse', fillcolor='#77DD77') |
19 | 23 | dot.node('ABORT', 'ABORT', shape='ellipse', fillcolor='#ff8f8f') |
20 | 24 | dot.node('A', 'FetchDataJob [db]') |
21 | | -dot.node('B', 'LoadLocalStoreJob', fillcolor='#ffefd5') |
22 | | -dot.node('C', 'OpenDbJob', fillcolor='#B0E0E6') |
23 | | -dot.node('D', 'ProcessDbMainJob', fillcolor='#B0E0E6') |
24 | | -dot.node('E', 'ProcessDbIndexJob', fillcolor='#B0E0E6:#ffefd5') |
25 | | -dot.node('M', 'FetchFileJob [file]') |
| 25 | +dot.node('B', 'LoadLocalStoreSigsJob', fillcolor='#ffefd5') |
| 26 | +dot.node('C', 'LoadLocalStoreJob', fillcolor='#ffefd5') |
| 27 | +dot.node('D', 'OpenDbJob', fillcolor='#B0E0E6') |
| 28 | +dot.node('E', 'MixStoreAndDbJob', fillcolor='#B0E0E6') |
| 29 | +dot.node('F', 'ProcessDbMainJob', fillcolor='#B0E0E6') |
| 30 | +dot.node('G', 'ProcessDbIndexJob', fillcolor='#B0E0E6:#ffefd5') |
| 31 | +dot.node('H', 'FetchFileJob [file]') |
26 | 32 |
|
27 | 33 | # Example "legend" nodes |
28 | 34 | dot.node('0', 'CPU', fillcolor='#B0E0E6') |
|
32 | 38 | dot.edge('START', 'A', label='1:N') |
33 | 39 | dot.edge('START', 'B') |
34 | 40 |
|
35 | | -dot.edge('A', 'C', weight='10') |
36 | | -dot.edge('C', 'D', weight='10', label=' db + store') |
37 | | -dot.edge('D', 'E', weight='10', label=' if no zips') |
| 41 | +dot.edge('A', 'D', weight='10') |
| 42 | +dot.edge('D', 'C', weight='5', constraint='false', label=' N:1, if any db sig != store sig') |
| 43 | +dot.edge('D', 'E', weight='10', label=' db') |
| 44 | +dot.edge('E', 'F', weight='10', label=' db + store') |
| 45 | +dot.edge('F', 'G', weight='10', label=' if no zips') |
| 46 | + |
| 47 | +dot.edge('G', 'H', label=' 1:N') |
| 48 | + |
| 49 | +dot.edge('C', 'E', style='dotted', constraint='true', label='wait\nstore', dir='back') |
| 50 | +dot.edge('B', 'D', style='dotted', constraint='true', label='wait\nstore sig', dir='back') |
| 51 | + |
| 52 | +# Position SKIP1 at same rank as OpenDbJob (D) |
| 53 | +with dot.subgraph() as s: |
| 54 | + s.attr(rank='same') |
| 55 | + s.node('SKIP1') |
| 56 | + s.node('D') |
| 57 | + s.node('C') |
38 | 58 |
|
39 | | -dot.edge('E', 'M', label=' 1:N') |
| 59 | +dot.edge('SKIP1', 'D', style='invis') |
| 60 | +dot.edge('D', 'C', style='invis') |
40 | 61 |
|
41 | | -dot.edge('B', 'C', style='dotted', constraint='true', label='wait\nstore', dir='back') |
| 62 | +# Position E, SKIP2, and ABORT at same rank (left to right) |
| 63 | +with dot.subgraph() as s: |
| 64 | + s.attr(rank='same') |
| 65 | + s.node('E') |
| 66 | + s.node('SKIP2') |
| 67 | + s.node('ABORT') |
42 | 68 |
|
43 | | -dot.edge('B', 'B', label=' retry', style='dashed', constraint='false') |
| 69 | +dot.edge('E', 'SKIP2', style='invis') |
| 70 | +dot.edge('SKIP2', 'ABORT', style='invis') |
| 71 | + |
| 72 | +dot.edge('C', 'C', label=' retry', style='dashed', constraint='false') |
44 | 73 | dot.edge('A', 'A', label=' retry', style='dashed', constraint='false') |
45 | | -dot.edge('C', 'A', label=' retry', style='dashed', constraint='true') |
46 | | -dot.edge('M', 'M', label=' retry', style='dashed', constraint='false') |
| 74 | +dot.edge('D', 'A', label=' retry', style='dashed', constraint='true') |
| 75 | +dot.edge('H', 'H', label=' retry', style='dashed', constraint='false') |
47 | 76 |
|
48 | | -dot.edge('M', 'END', weight='20', constraint='true') |
49 | | -dot.edge('B', 'ABORT', weight='20', constraint='true', label=' if always fails', style='dashed') |
| 77 | +dot.edge('H', 'END', weight='20', constraint='true') |
| 78 | +dot.edge('C', 'ABORT', weight='20', constraint='true', label=' if always fails', style='dashed', color=BACKUP_COLOR, fontcolor=BACKUP_COLOR) |
| 79 | +dot.edge('D', 'SKIP1', weight='1', constraint='false', label=' if db sig == store sig') |
| 80 | +dot.edge('E', 'SKIP2', weight='1', constraint='false', label=' if db sig == store sig') |
50 | 81 |
|
51 | 82 | dot.render('jobs_diagram', format='png', cleanup=True) |
52 | 83 |
|
|
55 | 86 | c.attr(style='filled', color='#f5f5ff', penwidth='1.0') |
56 | 87 | c.node('3', 'Zip Feature', style='filled', fillcolor='#8f8fff', fontcolor='white', penwidth='0') |
57 | 88 |
|
58 | | - c.node('O', 'WaitDbZipsJob', fillcolor='#B0E0E6') |
59 | | - c.node('F', 'ProcessZipIndexJob', fillcolor='#B0E0E6:#ffefd5') |
60 | | - c.node('G', 'FetchDataJob [zip summary]') |
61 | | - c.node('I', 'OpenZipSummaryJob', fillcolor='#B0E0E6') |
| 89 | + c.node('I', 'WaitDbZipsJob', fillcolor='#B0E0E6') |
| 90 | + c.node('J', 'ProcessZipIndexJob', fillcolor='#B0E0E6:#ffefd5') |
| 91 | + c.node('K', 'FetchDataJob [zip summary]') |
| 92 | + c.node('L', 'OpenZipSummaryJob', fillcolor='#B0E0E6') |
62 | 93 | c.node('DOT0', '', shape='circle', fixedsize='true', width='0.01', fillcolor='#ff8f8f') |
63 | | - c.node('J', 'FetchDataJob [zip contents]') |
64 | | - c.node('L', 'OpenZipContentsJob', fillcolor='#ffefd5') |
| 94 | + c.node('M', 'FetchDataJob [zip contents]') |
| 95 | + c.node('N', 'OpenZipContentsJob', fillcolor='#ffefd5') |
65 | 96 | c.node('DOT1', '', shape='circle', fixedsize='true', width='0.01', fillcolor='#ff8f8f') |
66 | 97 | c.node('DOT2', '', shape='circle', fixedsize='true', width='0.01', fillcolor='#ff8f8f') |
67 | 98 | # |
68 | 99 | # EDGES |
69 | 100 | # |
70 | | -dot.edge('D', 'O', weight='10', label='if zips') |
71 | | -dot.edge('O', 'E', weight='10', label='store w/ deselected\nzip indexes') |
72 | | -dot.edge('D', 'G', label='1:N (missing zips)') |
73 | | - |
74 | | -dot.edge('F', 'J', label='if many file installs') |
75 | | -dot.edge('I', 'F') |
76 | | -dot.edge('G', 'I') |
77 | | -dot.edge('J', 'L') |
78 | | -dot.edge('L', 'M', label='1:N\n(invalid files)') |
79 | | -dot.edge('F', 'DOT1', dir='none') |
| 101 | +dot.edge('F', 'I', weight='10', label='if zips') |
| 102 | +dot.edge('I', 'G', weight='10', label='store w/ deselected\nzip indexes') |
| 103 | +dot.edge('F', 'K', label='1:N (missing zips)') |
| 104 | + |
| 105 | +dot.edge('J', 'M', label='if many file installs') |
| 106 | +dot.edge('L', 'J') |
| 107 | +dot.edge('K', 'L') |
| 108 | +dot.edge('M', 'N') |
| 109 | +dot.edge('N', 'H', label='1:N\n(invalid files)') |
| 110 | +dot.edge('J', 'DOT1', dir='none') |
80 | 111 | dot.edge('DOT1', 'DOT2', label='if just few\n file installs', dir='none') |
81 | | -dot.edge('DOT2', 'M', label=' 1:N') |
82 | | -#dot.edge('L', 'M', label='1:N') |
| 112 | +dot.edge('DOT2', 'H', label=' 1:N') |
| 113 | +#dot.edge('N', 'H', label='1:N') |
83 | 114 |
|
84 | | -# “Wait” edges |
85 | | -dot.edge('F', 'O', style='dotted', constraint='true', label='wait\n zip indexes', dir='back') |
| 115 | +# "Wait" edges |
| 116 | +dot.edge('J', 'I', style='dotted', constraint='true', label='wait\n zip indexes', dir='back') |
86 | 117 |
|
87 | | -# Labeled “1:N” edges |
88 | | -dot.edge('D', 'F', label='1:N (stored zips)', weight='5') |
| 118 | +# Labeled "1:N" edges |
| 119 | +dot.edge('F', 'J', label='1:N (stored zips)', weight='5') |
89 | 120 |
|
90 | 121 | # Edges to END |
91 | | -dot.edge('L', 'END', weight='20', constraint='true') |
| 122 | +dot.edge('N', 'END', weight='20', constraint='true') |
92 | 123 |
|
93 | | -# “Retry” edges |
94 | | -dot.edge('G', 'G', label=' retry', style='dashed', constraint='false') |
95 | | -dot.edge('I', 'G', label=' retry', style='dashed', constraint='false') |
96 | | -dot.edge('J', 'J', label=' retry', style='dashed', constraint='false') |
97 | | -dot.edge('L', 'J', label=' retry', style='dashed', constraint='false') |
| 124 | +# "Retry" edges |
| 125 | +dot.edge('K', 'K', label=' retry', style='dashed', constraint='false') |
| 126 | +dot.edge('L', 'K', label=' retry', style='dashed', constraint='false') |
| 127 | +dot.edge('M', 'M', label=' retry', style='dashed', constraint='false') |
| 128 | +dot.edge('N', 'M', label=' retry', style='dashed', constraint='false') |
98 | 129 |
|
99 | 130 | # "Backup" edges |
100 | | -dot.edge('G', 'DOT0', style='dashed', constraint='true', dir='none') |
101 | | -dot.edge('I', 'DOT0', style='dashed', constraint='true', dir='none') |
102 | | -dot.edge('DOT0', 'F', label='backup:\nstored summary', style='dashed', constraint='false') |
| 131 | +dot.edge('K', 'DOT0', style='dashed', constraint='true', dir='none', color=BACKUP_COLOR) |
| 132 | +dot.edge('L', 'DOT0', style='dashed', constraint='true', dir='none', color=BACKUP_COLOR) |
| 133 | +dot.edge('DOT0', 'J', label='backup:\nstored summary', style='dashed', constraint='false', color=BACKUP_COLOR, fontcolor=BACKUP_COLOR) |
103 | 134 | #dot.edge('H', 'I', label='b', style='dashed', constraint='false', dir='none') |
104 | 135 | #dot.edge('I', 'F', label='b', style='dashed', constraint='false') |
105 | 136 | #dot.edge('J', 'E', label='b', style='dashed', constraint='false') |
|
0 commit comments