Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

graph.py 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # -*- coding: utf-8 -*-
  2. """
  3. The :program:`celery graph` command.
  4. .. program:: celery graph
  5. """
  6. from __future__ import absolute_import, unicode_literals
  7. from operator import itemgetter
  8. from celery.datastructures import DependencyGraph, GraphFormatter
  9. from celery.five import items
  10. from .base import Command
  11. __all__ = ['graph']
  12. class graph(Command):
  13. args = """<TYPE> [arguments]
  14. ..... bootsteps [worker] [consumer]
  15. ..... workers [enumerate]
  16. """
  17. def run(self, what=None, *args, **kwargs):
  18. map = {'bootsteps': self.bootsteps, 'workers': self.workers}
  19. if not what:
  20. raise self.UsageError('missing type')
  21. elif what not in map:
  22. raise self.Error('no graph {0} in {1}'.format(what, '|'.join(map)))
  23. return map[what](*args, **kwargs)
  24. def bootsteps(self, *args, **kwargs):
  25. worker = self.app.WorkController()
  26. include = set(arg.lower() for arg in args or ['worker', 'consumer'])
  27. if 'worker' in include:
  28. graph = worker.blueprint.graph
  29. if 'consumer' in include:
  30. worker.blueprint.connect_with(worker.consumer.blueprint)
  31. else:
  32. graph = worker.consumer.blueprint.graph
  33. graph.to_dot(self.stdout)
  34. def workers(self, *args, **kwargs):
  35. def simplearg(arg):
  36. return maybe_list(itemgetter(0, 2)(arg.partition(':')))
  37. def maybe_list(l, sep=','):
  38. return (l[0], l[1].split(sep) if sep in l[1] else l[1])
  39. args = dict(simplearg(arg) for arg in args)
  40. generic = 'generic' in args
  41. def generic_label(node):
  42. return '{0} ({1}://)'.format(type(node).__name__,
  43. node._label.split('://')[0])
  44. class Node(object):
  45. force_label = None
  46. scheme = {}
  47. def __init__(self, label, pos=None):
  48. self._label = label
  49. self.pos = pos
  50. def label(self):
  51. return self._label
  52. def __str__(self):
  53. return self.label()
  54. class Thread(Node):
  55. scheme = {'fillcolor': 'lightcyan4', 'fontcolor': 'yellow',
  56. 'shape': 'oval', 'fontsize': 10, 'width': 0.3,
  57. 'color': 'black'}
  58. def __init__(self, label, **kwargs):
  59. self._label = 'thr-{0}'.format(next(tids))
  60. self.real_label = label
  61. self.pos = 0
  62. class Formatter(GraphFormatter):
  63. def label(self, obj):
  64. return obj and obj.label()
  65. def node(self, obj):
  66. scheme = dict(obj.scheme) if obj.pos else obj.scheme
  67. if isinstance(obj, Thread):
  68. scheme['label'] = obj.real_label
  69. return self.draw_node(
  70. obj, dict(self.node_scheme, **scheme),
  71. )
  72. def terminal_node(self, obj):
  73. return self.draw_node(
  74. obj, dict(self.term_scheme, **obj.scheme),
  75. )
  76. def edge(self, a, b, **attrs):
  77. if isinstance(a, Thread):
  78. attrs.update(arrowhead='none', arrowtail='tee')
  79. return self.draw_edge(a, b, self.edge_scheme, attrs)
  80. def subscript(n):
  81. S = {'0': '₀', '1': '₁', '2': '₂', '3': '₃', '4': '₄',
  82. '5': '₅', '6': '₆', '7': '₇', '8': '₈', '9': '₉'}
  83. return ''.join([S[i] for i in str(n)])
  84. class Worker(Node):
  85. pass
  86. class Backend(Node):
  87. scheme = {'shape': 'folder', 'width': 2,
  88. 'height': 1, 'color': 'black',
  89. 'fillcolor': 'peachpuff3', 'color': 'peachpuff4'}
  90. def label(self):
  91. return generic_label(self) if generic else self._label
  92. class Broker(Node):
  93. scheme = {'shape': 'circle', 'fillcolor': 'cadetblue3',
  94. 'color': 'cadetblue4', 'height': 1}
  95. def label(self):
  96. return generic_label(self) if generic else self._label
  97. from itertools import count
  98. tids = count(1)
  99. Wmax = int(args.get('wmax', 4) or 0)
  100. Tmax = int(args.get('tmax', 3) or 0)
  101. def maybe_abbr(l, name, max=Wmax):
  102. size = len(l)
  103. abbr = max and size > max
  104. if 'enumerate' in args:
  105. l = ['{0}{1}'.format(name, subscript(i + 1))
  106. for i, obj in enumerate(l)]
  107. if abbr:
  108. l = l[0:max - 1] + [l[size - 1]]
  109. l[max - 2] = '{0}⎨…{1}⎬'.format(
  110. name[0], subscript(size - (max - 1)))
  111. return l
  112. try:
  113. workers = args['nodes']
  114. threads = args.get('threads') or []
  115. except KeyError:
  116. replies = self.app.control.inspect().stats()
  117. workers, threads = [], []
  118. for worker, reply in items(replies):
  119. workers.append(worker)
  120. threads.append(reply['pool']['max-concurrency'])
  121. wlen = len(workers)
  122. backend = args.get('backend', self.app.conf.CELERY_RESULT_BACKEND)
  123. threads_for = {}
  124. workers = maybe_abbr(workers, 'Worker')
  125. if Wmax and wlen > Wmax:
  126. threads = threads[0:3] + [threads[-1]]
  127. for i, threads in enumerate(threads):
  128. threads_for[workers[i]] = maybe_abbr(
  129. list(range(int(threads))), 'P', Tmax,
  130. )
  131. broker = Broker(args.get('broker', self.app.connection().as_uri()))
  132. backend = Backend(backend) if backend else None
  133. graph = DependencyGraph(formatter=Formatter())
  134. graph.add_arc(broker)
  135. if backend:
  136. graph.add_arc(backend)
  137. curworker = [0]
  138. for i, worker in enumerate(workers):
  139. worker = Worker(worker, pos=i)
  140. graph.add_arc(worker)
  141. graph.add_edge(worker, broker)
  142. if backend:
  143. graph.add_edge(worker, backend)
  144. threads = threads_for.get(worker._label)
  145. if threads:
  146. for thread in threads:
  147. thread = Thread(thread)
  148. graph.add_arc(thread)
  149. graph.add_edge(thread, worker)
  150. curworker[0] += 1
  151. graph.to_dot(self.stdout)