Просмотр исходного кода

add events for adding/removing process groups

Add ProcessGroupEvent abstract class.  Move groupname to header for these events.  Add tests

add docs

Add tests for process group add/remove events.  Remove test not yet passing.

set stopped_processes (not unstopped) in test_remove_process_group_event
btubbs 12 лет назад
Родитель
Сommit
27ec2ea1b9
7 измененных файлов с 125 добавлено и 1 удалено
  1. 46 1
      docs/events.rst
  2. 0 0
      stderr_logfile
  3. 0 0
      stdout_logfile
  4. 15 0
      supervisor/events.py
  5. 2 0
      supervisor/supervisord.py
  6. 24 0
      supervisor/tests/test_events.py
  7. 38 0
      supervisor/tests/test_supervisord.py

+ 46 - 1
docs/events.rst

@@ -203,7 +203,7 @@ notification is as follows.
 
 
 .. code-block:: text
 .. code-block:: text
 
 
-   process_name:foo group_name:bar pid:123
+   processname:foo groupname:bar pid:123
    This is the data that was sent between the tags
    This is the data that was sent between the tags
 
 
 The payload structure of any given event is determined only by the
 The payload structure of any given event is determined only by the
@@ -846,3 +846,48 @@ indicates the epoch time for which the tick was sent.
 
 
    when:1201063880
    when:1201063880
 
 
+``PROCESS_GROUP`` Event Type
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An event type raised when a process group is added to or removed from
+Supervisor.  This type is abstract, it will never be sent
+directly.  Subscribing to this event type will cause a subscriber to
+receive event notifications of all the subtypes of
+``PROCESS_GROUP``.
+
+*Name*: ``PROCESS_GROUP``
+
+*Subtype Of*: ``EVENT``
+
+*Body Description*: N/A
+
+``PROCESS_GROUP_ADDED`` Event Type
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Indicates that a process group has been added to Supervisor's configuration. 
+
+*Name*: ``PROCESS_GROUP_ADDED``
+
+*Subtype Of*: ``PROCESS_GROUP``
+
+*Body Description*: This body is a token set with just a groupname key/value.
+
+.. code-block:: text
+
+   groupname:cat
+
+``PROCESS_GROUP_REMOVED`` Event Type
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Indicates that a process group has been removed from Supervisor's configuration. 
+
+*Name*: ``PROCESS_GROUP_REMOVED``
+
+*Subtype Of*: ``PROCESS_GROUP``
+
+*Body Description*: This body is a token set with just a groupname key/value.
+
+.. code-block:: text
+
+   groupname:cat
+

+ 0 - 0
stderr_logfile


+ 0 - 0
stdout_logfile


+ 15 - 0
supervisor/events.py

@@ -151,6 +151,18 @@ class ProcessStateStoppedEvent(ProcessStateEvent):
     def get_extra_values(self):
     def get_extra_values(self):
         return [('pid', self.process.pid)]
         return [('pid', self.process.pid)]
 
 
+class ProcessGroupEvent(Event):
+    def __init__(self, group):
+        self.group = group
+    def __str__(self):
+        return 'groupname:%s\n' % self.group
+
+class ProcessGroupAddedEvent(ProcessGroupEvent):
+    pass
+
+class ProcessGroupRemovedEvent(ProcessGroupEvent):
+    pass
+
 class TickEvent(Event):
 class TickEvent(Event):
     """ Abstract """
     """ Abstract """
     def __init__(self, when, supervisord):
     def __init__(self, when, supervisord):
@@ -196,6 +208,9 @@ class EventTypes:
     TICK_5 = Tick5Event
     TICK_5 = Tick5Event
     TICK_60 = Tick60Event
     TICK_60 = Tick60Event
     TICK_3600 = Tick3600Event
     TICK_3600 = Tick3600Event
+    PROCESS_GROUP = ProcessGroupEvent # abstract
+    PROCESS_GROUP_ADDED = ProcessGroupAddedEvent
+    PROCESS_GROUP_REMOVED = ProcessGroupRemovedEvent
 
 
 def getEventNameByType(requested):
 def getEventNameByType(requested):
     for name, typ in EventTypes.__dict__.items():
     for name, typ in EventTypes.__dict__.items():

+ 2 - 0
supervisor/supervisord.py

@@ -122,6 +122,7 @@ class Supervisor:
         if name not in self.process_groups:
         if name not in self.process_groups:
             config.after_setuid()
             config.after_setuid()
             self.process_groups[name] = config.make_group()
             self.process_groups[name] = config.make_group()
+            events.notify(events.ProcessGroupAddedEvent(name))
             return True
             return True
         return False
         return False
 
 
@@ -129,6 +130,7 @@ class Supervisor:
         if self.process_groups[name].get_unstopped_processes():
         if self.process_groups[name].get_unstopped_processes():
             return False
             return False
         del self.process_groups[name]
         del self.process_groups[name]
+        events.notify(events.ProcessGroupRemovedEvent(name))
         return True
         return True
 
 
     def get_process_map(self):
     def get_process_map(self):

+ 24 - 0
supervisor/tests/test_events.py

@@ -242,6 +242,16 @@ class TestEventTypes(unittest.TestCase):
         inst = klass(1, 2)
         inst = klass(1, 2)
         self.assertEqual(inst.when, 1)
         self.assertEqual(inst.when, 1)
         self.assertEqual(inst.supervisord, 2)
         self.assertEqual(inst.supervisord, 2)
+
+    def test_ProcessGroupAddedEvent_attributes(self):
+        from supervisor.events import ProcessGroupAddedEvent
+        inst = ProcessGroupAddedEvent('myprocess')
+        self.assertEqual(inst.group, 'myprocess')
+
+    def test_ProcessGroupRemovedEvent_attributes(self):
+        from supervisor.events import ProcessGroupRemovedEvent
+        inst = ProcessGroupRemovedEvent('myprocess')
+        self.assertEqual(inst.group, 'myprocess')
         
         
 class TestSerializations(unittest.TestCase):
 class TestSerializations(unittest.TestCase):
     def _deserialize(self, serialization):
     def _deserialize(self, serialization):
@@ -327,6 +337,20 @@ class TestSerializations(unittest.TestCase):
         self.assertEqual(headers['type'], 'foo', headers)
         self.assertEqual(headers['type'], 'foo', headers)
         self.assertEqual(payload, 'bar')
         self.assertEqual(payload, 'bar')
 
 
+    def test_process_group_added_event(self):
+        from supervisor.events import ProcessGroupAddedEvent
+        event = ProcessGroupAddedEvent('foo')
+        headers, payload = self._deserialize(str(event))
+        self.assertEqual(headers['groupname'], 'foo')
+        self.assertEqual(payload, '')
+
+    def test_process_group_removed_event(self):
+        from supervisor.events import ProcessGroupRemovedEvent
+        event = ProcessGroupRemovedEvent('foo')
+        headers, payload = self._deserialize(str(event))
+        self.assertEqual(headers['groupname'], 'foo')
+        self.assertEqual(payload, '')
+
     def test_process_state_events_without_extra_values(self):
     def test_process_state_events_without_extra_values(self):
         from supervisor.states import ProcessStates
         from supervisor.states import ProcessStates
         from supervisor import events
         from supervisor import events

+ 38 - 0
supervisor/tests/test_supervisord.py

@@ -323,6 +323,24 @@ class SupervisordTests(unittest.TestCase):
         self.assertEqual(group, supervisord.process_groups['foo'])
         self.assertEqual(group, supervisord.process_groups['foo'])
         self.assertTrue(not result)
         self.assertTrue(not result)
 
 
+    def test_add_process_group_event(self):
+        from supervisor import events
+        L = []
+        def callback(event):
+            L.append(1)
+        events.subscribe(events.ProcessGroupAddedEvent, callback)
+        options = DummyOptions()
+        pconfig = DummyPConfig(options, 'foo', 'foo', '/bin/foo')
+        gconfig = DummyPGroupConfig(options,'foo', pconfigs=[pconfig])
+        options.process_group_configs = [gconfig]
+        supervisord = self._makeOne(options)
+
+        supervisord.add_process_group(gconfig)
+
+        options.test = True
+        supervisord.runforever()
+        self.assertEqual(L, [1])
+
     def test_remove_process_group(self):
     def test_remove_process_group(self):
         options = DummyOptions()
         options = DummyOptions()
         pconfig = DummyPConfig(options, 'foo', 'foo', '/bin/foo')
         pconfig = DummyPConfig(options, 'foo', 'foo', '/bin/foo')
@@ -342,6 +360,26 @@ class SupervisordTests(unittest.TestCase):
         self.assertEqual(supervisord.process_groups.keys(), ['foo'])
         self.assertEqual(supervisord.process_groups.keys(), ['foo'])
         self.assertTrue(not result)
         self.assertTrue(not result)
 
 
+    def test_remove_process_group_event(self):
+        from supervisor import events
+        L = []
+        def callback(event):
+            L.append(1)
+        events.subscribe(events.ProcessGroupRemovedEvent, callback)
+        options = DummyOptions()
+        pconfig = DummyPConfig(options, 'foo', 'foo', '/bin/foo')
+        gconfig = DummyPGroupConfig(options,'foo', pconfigs=[pconfig])
+        options.process_group_configs = [gconfig]
+        supervisord = self._makeOne(options)
+
+        supervisord.add_process_group(gconfig)
+        supervisord.process_groups['foo'].stopped_processes = [DummyProcess(None)]
+        supervisord.remove_process_group('foo')
+        options.test = True
+        supervisord.runforever()
+
+        self.assertEqual(L, [1])
+
     def test_runforever_emits_generic_startup_event(self):
     def test_runforever_emits_generic_startup_event(self):
         from supervisor import events
         from supervisor import events
         L = []
         L = []