events.py 6.5 KB

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