Explorar o código

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 %!s(int64=12) %!d(string=hai) anos
pai
achega
27ec2ea1b9

+ 46 - 1
docs/events.rst

@@ -203,7 +203,7 @@ notification is as follows.
 
 .. 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
 
 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
 
+``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):
         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):
     """ Abstract """
     def __init__(self, when, supervisord):
@@ -196,6 +208,9 @@ class EventTypes:
     TICK_5 = Tick5Event
     TICK_60 = Tick60Event
     TICK_3600 = Tick3600Event
+    PROCESS_GROUP = ProcessGroupEvent # abstract
+    PROCESS_GROUP_ADDED = ProcessGroupAddedEvent
+    PROCESS_GROUP_REMOVED = ProcessGroupRemovedEvent
 
 def getEventNameByType(requested):
     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:
             config.after_setuid()
             self.process_groups[name] = config.make_group()
+            events.notify(events.ProcessGroupAddedEvent(name))
             return True
         return False
 
@@ -129,6 +130,7 @@ class Supervisor:
         if self.process_groups[name].get_unstopped_processes():
             return False
         del self.process_groups[name]
+        events.notify(events.ProcessGroupRemovedEvent(name))
         return True
 
     def get_process_map(self):

+ 24 - 0
supervisor/tests/test_events.py

@@ -242,6 +242,16 @@ class TestEventTypes(unittest.TestCase):
         inst = klass(1, 2)
         self.assertEqual(inst.when, 1)
         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):
     def _deserialize(self, serialization):
@@ -327,6 +337,20 @@ class TestSerializations(unittest.TestCase):
         self.assertEqual(headers['type'], 'foo', headers)
         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):
         from supervisor.states import ProcessStates
         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.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):
         options = DummyOptions()
         pconfig = DummyPConfig(options, 'foo', 'foo', '/bin/foo')
@@ -342,6 +360,26 @@ class SupervisordTests(unittest.TestCase):
         self.assertEqual(supervisord.process_groups.keys(), ['foo'])
         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):
         from supervisor import events
         L = []