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
1=== modified file 'src/maasserver/listener.py'
2--- src/maasserver/listener.py 2016-10-24 14:02:17 +0000
3+++ src/maasserver/listener.py 2016-11-10 06:48:22 +0000
4@@ -160,8 +160,20 @@
5 if self.isSystemChannel(notify.channel):
6 # System level message; pass it to the registered
7 # handler immediately.
8- handler = self.listeners[notify.channel][0]
9- handler(notify.channel, notify.payload)
10+ if notify.channel in self.listeners:
11+ # Be defensive in that if a handler does not exist
12+ # for this channel then the channel should be
13+ # unregisted and removed from listeners.
14+ if len(self.listeners[notify.channel]) > 0:
15+ handler = self.listeners[notify.channel][0]
16+ handler(notify.channel, notify.payload)
17+ else:
18+ self.unregisterChannel(notify.channel)
19+ del self.listeners[notify.channel]
20+ else:
21+ # Unregister the channel since no listener is
22+ # registered for this channel.
23+ self.unregisterChannel(notify.channel)
24 else:
25 # Place non-system messages into the queue to be
26 # processed.
27
28=== modified file 'src/maasserver/tests/test_listener.py'
29--- src/maasserver/tests/test_listener.py 2016-10-24 14:02:17 +0000
30+++ src/maasserver/tests/test_listener.py 2016-11-10 06:48:22 +0000
31@@ -110,6 +110,39 @@
32
33 @wait_for_reactor
34 @inlineCallbacks
35+ def test__handles_missing_system_handler_on_notification(self):
36+ listener = PostgresListenerService()
37+ # Change notifications to a frozenset. This makes sure that
38+ # the system message does not go into the queue. Instead if should
39+ # call the handler directly in `doRead`.
40+ listener.notifications = frozenset()
41+ yield listener.startService()
42+ yield deferToDatabase(listener.registerChannel, "sys_test")
43+ listener.listeners["sys_test"] = []
44+ try:
45+ yield deferToDatabase(self.send_notification, "sys_test", 1)
46+ self.assertFalse("sys_test" in listener.listeners)
47+ finally:
48+ yield listener.stopService()
49+
50+ @wait_for_reactor
51+ @inlineCallbacks
52+ def test__handles_missing_notify_system_listener_on_notification(self):
53+ listener = PostgresListenerService()
54+ # Change notifications to a frozenset. This makes sure that
55+ # the system message does not go into the queue. Instead if should
56+ # call the handler directly in `doRead`.
57+ listener.notifications = frozenset()
58+ yield listener.startService()
59+ yield deferToDatabase(listener.registerChannel, "sys_test")
60+ try:
61+ yield deferToDatabase(self.send_notification, "sys_test", 1)
62+ self.assertFalse("sys_test" in listener.listeners)
63+ finally:
64+ yield listener.stopService()
65+
66+ @wait_for_reactor
67+ @inlineCallbacks
68 def test__calls_handler_on_notification(self):
69 listener = PostgresListenerService()
70 dv = DeferredValue()