Merge lp:~blake-rouse/maas/fix-1640300 into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 5550
Proposed branch: lp:~blake-rouse/maas/fix-1640300
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 70 lines (+47/-2)
2 files modified
src/maasserver/listener.py (+14/-2)
src/maasserver/tests/test_listener.py (+33/-0)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1640300
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+310506@code.launchpad.net

Commit message

Be defensive in the postgresql listener when a system notification is received for a none existed handler or missing listener channel.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

Looks good, but I don't understand how it fixes the bug.

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote :

I believe this fixes the bug because the failure was causing continuous failures to handle that notification which was grabbing lots of connections to the database.

It floods the logs on the attached bug. This is the only reason I can see him getting that strange error from postgresql.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/listener.py'
--- src/maasserver/listener.py 2016-10-24 14:02:17 +0000
+++ src/maasserver/listener.py 2016-11-10 06:48:22 +0000
@@ -160,8 +160,20 @@
160 if self.isSystemChannel(notify.channel):160 if self.isSystemChannel(notify.channel):
161 # System level message; pass it to the registered161 # System level message; pass it to the registered
162 # handler immediately.162 # handler immediately.
163 handler = self.listeners[notify.channel][0]163 if notify.channel in self.listeners:
164 handler(notify.channel, notify.payload)164 # Be defensive in that if a handler does not exist
165 # for this channel then the channel should be
166 # unregisted and removed from listeners.
167 if len(self.listeners[notify.channel]) > 0:
168 handler = self.listeners[notify.channel][0]
169 handler(notify.channel, notify.payload)
170 else:
171 self.unregisterChannel(notify.channel)
172 del self.listeners[notify.channel]
173 else:
174 # Unregister the channel since no listener is
175 # registered for this channel.
176 self.unregisterChannel(notify.channel)
165 else:177 else:
166 # Place non-system messages into the queue to be178 # Place non-system messages into the queue to be
167 # processed.179 # processed.
168180
=== modified file 'src/maasserver/tests/test_listener.py'
--- src/maasserver/tests/test_listener.py 2016-10-24 14:02:17 +0000
+++ src/maasserver/tests/test_listener.py 2016-11-10 06:48:22 +0000
@@ -110,6 +110,39 @@
110110
111 @wait_for_reactor111 @wait_for_reactor
112 @inlineCallbacks112 @inlineCallbacks
113 def test__handles_missing_system_handler_on_notification(self):
114 listener = PostgresListenerService()
115 # Change notifications to a frozenset. This makes sure that
116 # the system message does not go into the queue. Instead if should
117 # call the handler directly in `doRead`.
118 listener.notifications = frozenset()
119 yield listener.startService()
120 yield deferToDatabase(listener.registerChannel, "sys_test")
121 listener.listeners["sys_test"] = []
122 try:
123 yield deferToDatabase(self.send_notification, "sys_test", 1)
124 self.assertFalse("sys_test" in listener.listeners)
125 finally:
126 yield listener.stopService()
127
128 @wait_for_reactor
129 @inlineCallbacks
130 def test__handles_missing_notify_system_listener_on_notification(self):
131 listener = PostgresListenerService()
132 # Change notifications to a frozenset. This makes sure that
133 # the system message does not go into the queue. Instead if should
134 # call the handler directly in `doRead`.
135 listener.notifications = frozenset()
136 yield listener.startService()
137 yield deferToDatabase(listener.registerChannel, "sys_test")
138 try:
139 yield deferToDatabase(self.send_notification, "sys_test", 1)
140 self.assertFalse("sys_test" in listener.listeners)
141 finally:
142 yield listener.stopService()
143
144 @wait_for_reactor
145 @inlineCallbacks
113 def test__calls_handler_on_notification(self):146 def test__calls_handler_on_notification(self):
114 listener = PostgresListenerService()147 listener = PostgresListenerService()
115 dv = DeferredValue()148 dv = DeferredValue()