Merge ~cjwatson/launchpad:number-cruncher-errors into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: a39bde1cef6f661765dde65e0dce4317def5e379
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:number-cruncher-errors
Merge into: launchpad:master
Diff against target: 98 lines (+44/-11)
2 files modified
lib/lp/services/statsd/numbercruncher.py (+18/-11)
lib/lp/services/statsd/tests/test_numbercruncher.py (+26/-0)
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Review via email: mp+393599@code.launchpad.net

Commit message

Handle errors in number-cruncher loops

Description of the change

If a LoopingCall raises an exception, then Twisted won't schedule it to be called again. Log any exceptions and return normally instead.

To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/services/statsd/numbercruncher.py b/lib/lp/services/statsd/numbercruncher.py
2index 85fa2cd..6a43c36 100644
3--- a/lib/lp/services/statsd/numbercruncher.py
4+++ b/lib/lp/services/statsd/numbercruncher.py
5@@ -74,15 +74,19 @@ class NumberCruncher(service.Service):
6 This aborts the current transaction before returning.
7 """
8 self.logger.debug("Updating build queue stats.")
9- queue_details = getUtility(IBuilderSet).getBuildQueueSizes()
10- for queue_type, contents in queue_details.items():
11- virt = queue_type == 'virt'
12- for arch, value in contents.items():
13- gauge_name = "buildqueue,virtualized={},arch={},env={}".format(
14- virt, arch, self.statsd_client.lp_environment)
15- self.logger.debug("{}: {}".format(gauge_name, value[0]))
16- self.statsd_client.gauge(gauge_name, value[0])
17- self.logger.debug("Build queue stats update complete.")
18+ try:
19+ queue_details = getUtility(IBuilderSet).getBuildQueueSizes()
20+ for queue_type, contents in queue_details.items():
21+ virt = queue_type == 'virt'
22+ for arch, value in contents.items():
23+ gauge_name = (
24+ "buildqueue,virtualized={},arch={},env={}".format(
25+ virt, arch, self.statsd_client.lp_environment))
26+ self.logger.debug("{}: {}".format(gauge_name, value[0]))
27+ self.statsd_client.gauge(gauge_name, value[0])
28+ self.logger.debug("Build queue stats update complete.")
29+ except Exception:
30+ self.logger.exception("Failure while updating build queue stats:")
31 transaction.abort()
32
33 def _updateBuilderCounts(self):
34@@ -123,8 +127,11 @@ class NumberCruncher(service.Service):
35
36 This aborts the current transaction before returning.
37 """
38- self.builder_factory.update()
39- self._updateBuilderCounts()
40+ try:
41+ self.builder_factory.update()
42+ self._updateBuilderCounts()
43+ except Exception:
44+ self.logger.exception("Failure while updating builder stats:")
45 transaction.abort()
46
47 def startService(self):
48diff --git a/lib/lp/services/statsd/tests/test_numbercruncher.py b/lib/lp/services/statsd/tests/test_numbercruncher.py
49index ede74e1..020ef76 100644
50--- a/lib/lp/services/statsd/tests/test_numbercruncher.py
51+++ b/lib/lp/services/statsd/tests/test_numbercruncher.py
52@@ -21,6 +21,8 @@ from lp.buildmaster.interactor import BuilderSlave
53 from lp.buildmaster.interfaces.processor import IProcessorSet
54 from lp.buildmaster.tests.mock_slaves import OkSlave
55 from lp.services.database.isolation import is_transaction_in_progress
56+from lp.services.database.policy import DatabaseBlockedPolicy
57+from lp.services.log.logger import BufferLogger
58 from lp.services.statsd.numbercruncher import NumberCruncher
59 from lp.services.statsd.tests import StatsMixin
60 from lp.testing import TestCaseWithFactory
61@@ -103,6 +105,18 @@ class TestNumberCruncher(StatsMixin, TestCaseWithFactory):
62 'virtualized=True,env=test', 1))
63 ]))
64
65+ def test_updateBuilderStats_error(self):
66+ clock = task.Clock()
67+ cruncher = NumberCruncher(clock=clock)
68+ cruncher.logger = BufferLogger()
69+ with DatabaseBlockedPolicy():
70+ cruncher.updateBuilderStats()
71+
72+ self.assertFalse(is_transaction_in_progress())
73+ self.assertIn(
74+ "Failure while updating builder stats:",
75+ cruncher.logger.getLogBuffer())
76+
77 def test_updateBuilderQueues(self):
78 builder = self.factory.makeBuilder(
79 processors=[getUtility(IProcessorSet).getByName('amd64')])
80@@ -127,6 +141,18 @@ class TestNumberCruncher(StatsMixin, TestCaseWithFactory):
81 Equals(('buildqueue,virtualized=False,arch=386,env=test', 1))
82 ]))
83
84+ def test_updateBuilderQueues_error(self):
85+ clock = task.Clock()
86+ cruncher = NumberCruncher(clock=clock)
87+ cruncher.logger = BufferLogger()
88+ with DatabaseBlockedPolicy():
89+ cruncher.updateBuilderQueues()
90+
91+ self.assertFalse(is_transaction_in_progress())
92+ self.assertIn(
93+ "Failure while updating build queue stats:",
94+ cruncher.logger.getLogBuffer())
95+
96 def test_startService_starts_update_queues_loop(self):
97 clock = task.Clock()
98 cruncher = NumberCruncher(clock=clock)

Subscribers

People subscribed via source and target branches

to status/vote changes: