events.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. from supervisor.states import getProcessStateDescription
  2. callbacks = []
  3. def subscribe(type, callback):
  4. callbacks.append((type, callback))
  5. def notify(event):
  6. for type, callback in callbacks:
  7. if isinstance(event, type):
  8. callback(event)
  9. def clear():
  10. callbacks[:] = []
  11. class Event:
  12. """ Abstract event type """
  13. pass
  14. class ProcessLogEvent(Event):
  15. """ Abstract """
  16. def __init__(self, process, pid, data):
  17. self.process = process
  18. self.pid = pid
  19. self.data = data
  20. def __str__(self):
  21. groupname = ''
  22. if self.process.group is not None:
  23. groupname = self.process.group.config.name
  24. return 'processname:%s groupname:%s pid:%s channel:%s\n%s' % (
  25. self.process.config.name,
  26. groupname,
  27. self.pid,
  28. self.channel,
  29. self.data)
  30. class ProcessLogStdoutEvent(ProcessLogEvent):
  31. channel = 'stdout'
  32. class ProcessLogStderrEvent(ProcessLogEvent):
  33. channel = 'stderr'
  34. class ProcessCommunicationEvent(Event):
  35. """ Abstract """
  36. # event mode tokens
  37. BEGIN_TOKEN = '<!--XSUPERVISOR:BEGIN-->'
  38. END_TOKEN = '<!--XSUPERVISOR:END-->'
  39. def __init__(self, process, pid, data):
  40. self.process = process
  41. self.pid = pid
  42. self.data = data
  43. def __str__(self):
  44. groupname = ''
  45. if self.process.group is not None:
  46. groupname = self.process.group.config.name
  47. return 'processname:%s groupname:%s pid:%s\n%s' % (
  48. self.process.config.name,
  49. groupname,
  50. self.pid,
  51. self.data)
  52. class ProcessCommunicationStdoutEvent(ProcessCommunicationEvent):
  53. channel = 'stdout'
  54. class ProcessCommunicationStderrEvent(ProcessCommunicationEvent):
  55. channel = 'stderr'
  56. class RemoteCommunicationEvent(Event):
  57. def __init__(self, type, data):
  58. self.type = type
  59. self.data = data
  60. def __str__(self):
  61. return 'type:%s\n%s' % (self.type, self.data)
  62. class SupervisorStateChangeEvent(Event):
  63. """ Abstract class """
  64. def __str__(self):
  65. return ''
  66. class SupervisorRunningEvent(SupervisorStateChangeEvent):
  67. pass
  68. class SupervisorStoppingEvent(SupervisorStateChangeEvent):
  69. pass
  70. class EventRejectedEvent: # purposely does not subclass Event
  71. def __init__(self, process, event):
  72. self.process = process
  73. self.event = event
  74. class ProcessStateEvent(Event):
  75. """ Abstract class, never raised directly """
  76. frm = None
  77. to = None
  78. def __init__(self, process, from_state, expected=True):
  79. self.process = process
  80. self.from_state = from_state
  81. self.expected = expected
  82. # we eagerly render these so if the process pid, etc changes beneath
  83. # us, we stash the values at the time the event was sent
  84. self.extra_values = self.get_extra_values()
  85. def __str__(self):
  86. groupname = ''
  87. if self.process.group is not None:
  88. groupname = self.process.group.config.name
  89. L = []
  90. L.append(('processname', self.process.config.name))
  91. L.append(('groupname', groupname))
  92. L.append(('from_state', getProcessStateDescription(self.from_state)))
  93. L.extend(self.extra_values)
  94. s = ' '.join( [ '%s:%s' % (name, val) for (name, val) in L ] )
  95. return s
  96. def get_extra_values(self):
  97. return []
  98. class ProcessStateFatalEvent(ProcessStateEvent):
  99. pass
  100. class ProcessStateUnknownEvent(ProcessStateEvent):
  101. pass
  102. class ProcessStateStartingOrBackoffEvent(ProcessStateEvent):
  103. def get_extra_values(self):
  104. return [('tries', int(self.process.backoff))]
  105. class ProcessStateBackoffEvent(ProcessStateStartingOrBackoffEvent):
  106. pass
  107. class ProcessStateStartingEvent(ProcessStateStartingOrBackoffEvent):
  108. pass
  109. class ProcessStateExitedEvent(ProcessStateEvent):
  110. def get_extra_values(self):
  111. return [('expected', int(self.expected)), ('pid', self.process.pid)]
  112. class ProcessStateRunningEvent(ProcessStateEvent):
  113. def get_extra_values(self):
  114. return [('pid', self.process.pid)]
  115. class ProcessStateStoppingEvent(ProcessStateEvent):
  116. def get_extra_values(self):
  117. return [('pid', self.process.pid)]
  118. class ProcessStateStoppedEvent(ProcessStateEvent):
  119. def get_extra_values(self):
  120. return [('pid', self.process.pid)]
  121. class ProcessGroupEvent(Event):
  122. def __init__(self, group):
  123. self.group = group
  124. def __str__(self):
  125. return 'groupname:%s\n' % self.group
  126. class ProcessGroupAddedEvent(ProcessGroupEvent):
  127. pass
  128. class ProcessGroupRemovedEvent(ProcessGroupEvent):
  129. pass
  130. class TickEvent(Event):
  131. """ Abstract """
  132. def __init__(self, when, supervisord):
  133. self.when = when
  134. self.supervisord = supervisord
  135. def __str__(self):
  136. return 'when:%s' % self.when
  137. class Tick5Event(TickEvent):
  138. period = 5
  139. class Tick60Event(TickEvent):
  140. period = 60
  141. class Tick3600Event(TickEvent):
  142. period = 3600
  143. TICK_EVENTS = [ Tick5Event, Tick60Event, Tick3600Event ] # imported elsewhere
  144. class EventTypes:
  145. EVENT = Event # abstract
  146. PROCESS_STATE = ProcessStateEvent # abstract
  147. PROCESS_STATE_STOPPED = ProcessStateStoppedEvent
  148. PROCESS_STATE_EXITED = ProcessStateExitedEvent
  149. PROCESS_STATE_STARTING = ProcessStateStartingEvent
  150. PROCESS_STATE_STOPPING = ProcessStateStoppingEvent
  151. PROCESS_STATE_BACKOFF = ProcessStateBackoffEvent
  152. PROCESS_STATE_FATAL = ProcessStateFatalEvent
  153. PROCESS_STATE_RUNNING = ProcessStateRunningEvent
  154. PROCESS_STATE_UNKNOWN = ProcessStateUnknownEvent
  155. PROCESS_COMMUNICATION = ProcessCommunicationEvent # abstract
  156. PROCESS_COMMUNICATION_STDOUT = ProcessCommunicationStdoutEvent
  157. PROCESS_COMMUNICATION_STDERR = ProcessCommunicationStderrEvent
  158. PROCESS_LOG = ProcessLogEvent
  159. PROCESS_LOG_STDOUT = ProcessLogStdoutEvent
  160. PROCESS_LOG_STDERR = ProcessLogStderrEvent
  161. REMOTE_COMMUNICATION = RemoteCommunicationEvent
  162. SUPERVISOR_STATE_CHANGE = SupervisorStateChangeEvent # abstract
  163. SUPERVISOR_STATE_CHANGE_RUNNING = SupervisorRunningEvent
  164. SUPERVISOR_STATE_CHANGE_STOPPING = SupervisorStoppingEvent
  165. TICK = TickEvent # abstract
  166. TICK_5 = Tick5Event
  167. TICK_60 = Tick60Event
  168. TICK_3600 = Tick3600Event
  169. PROCESS_GROUP = ProcessGroupEvent # abstract
  170. PROCESS_GROUP_ADDED = ProcessGroupAddedEvent
  171. PROCESS_GROUP_REMOVED = ProcessGroupRemovedEvent
  172. def getEventNameByType(requested):
  173. for name, typ in EventTypes.__dict__.items():
  174. if typ is requested:
  175. return name
  176. def register(name, event):
  177. EventTypes.__dict__[name] = event