Merge lp:~jelmer/launchpad/robust-process-accepted into lp:launchpad

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~jelmer/launchpad/robust-process-accepted
Merge into: lp:launchpad
Diff against target: 156 lines (+68/-18)
2 files modified
lib/lp/soyuz/scripts/processaccepted.py (+13/-5)
lib/lp/soyuz/tests/test_processaccepted.py (+55/-13)
To merge this branch: bzr merge lp:~jelmer/launchpad/robust-process-accepted
Reviewer Review Type Date Requested Status
Henning Eggers (community) code Approve
Review via email: mp+23312@code.launchpad.net

Commit message

Log OOPSes when encountering errors in process-accepted and skip just the problematic item rather than aborting.

Description of the change

This branch should make process-accepted a bit more robust. It changes it to file an OOPS when it encounters an exception while processing an item in the queue, rather than re-raising that exception, skipping the processing of the rest of the queue and rolling back the transactions.

This should make it impossible for a single problematic package to block process-accepted, as happened about a week ago.

To post a comment you must log in.
Revision history for this message
Henning Eggers (henninge) wrote :
Download full text (7.4 KiB)

Am 13.04.2010 13:57, schrieb Jelmer Vernooij:
> This branch should make process-accepted a bit more robust. It changes it to file an OOPS when it encounters an exception while processing an item in the queue, rather than re-raising that exception, skipping the processing of the rest of the queue and rolling back the transactions.
>
> This should make it impossible for a single problematic package to block process-accepted, as happened about a week ago.

Very good, thank you for fixing this!

> === modified file 'lib/lp/soyuz/scripts/processaccepted.py'
> --- lib/lp/soyuz/scripts/processaccepted.py 2010-02-23 10:30:56 +0000
> +++ lib/lp/soyuz/scripts/processaccepted.py 2010-04-13 11:56:59 +0000
> @@ -11,12 +11,16 @@
> 'ProcessAccepted',
> ]
>
> +import sys
> +
> from zope.component import getUtility
>
> from lp.archiveuploader.tagfiles import parse_tagfile_lines
> from lp.bugs.interfaces.bug import IBugSet
> from lp.bugs.interfaces.bugtask import BugTaskStatus
> from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
> +from canonical.launchpad.webapp.errorlog import (
> + ErrorReportingUtility, ScriptRequest)
> from canonical.launchpad.webapp.interfaces import NotFoundError
> from lp.soyuz.interfaces.archive import ArchivePurpose, IArchiveSet
> from lp.registry.interfaces.distribution import IDistributionSet
> @@ -244,11 +248,15 @@
> for queue_item in queue_items:
> try:
> queue_item.realiseUpload(self.logger)

Um, I thought we use en_US as the standard language ... ;-)
Not for you to fix here, though. (realizeUpload)

> - except:
> - self.logger.error(
> - "Failure processing queue_item %d" % (
> - queue_item.id), exc_info=True)
> - raise
> + except Exception:
> + message = "Failure processing queue_item %d" % (
> + queue_item.id)
> + properties = [('error-explanation', message)]
> + request = ScriptRequest(properties)
> + error_utility = ErrorReportingUtility()
> + error_utility.raising(sys.exc_info(), request)
> + self.logger.error('%s (%s)' % (message,
> + request.oopsid))

Please put the newline right after the opening "(", as I think that conforms more to our coding style (similar to a function call in looks).

                            self.logger.error('%s (%s)' % (
                                message, request.oopsid))

I have never had to file an OOPS before so I trust that this is the right way to do it.

> else:
> processed_queue_ids.append(queue_item.id)
>
>
> === modified file 'lib/lp/soyuz/tests/test_processaccepted.py'
> --- lib/lp/soyuz/tests/test_processaccepted.py 2010-02-23 10:30:56 +0000
> +++ lib/lp/soyuz/tests/test_processaccepted.py 2010-04-13 11:56:59 +0...

Read more...

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/scripts/processaccepted.py'
2--- lib/lp/soyuz/scripts/processaccepted.py 2010-02-23 10:30:56 +0000
3+++ lib/lp/soyuz/scripts/processaccepted.py 2010-04-13 13:58:19 +0000
4@@ -11,12 +11,16 @@
5 'ProcessAccepted',
6 ]
7
8+import sys
9+
10 from zope.component import getUtility
11
12 from lp.archiveuploader.tagfiles import parse_tagfile_lines
13 from lp.bugs.interfaces.bug import IBugSet
14 from lp.bugs.interfaces.bugtask import BugTaskStatus
15 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
16+from canonical.launchpad.webapp.errorlog import (
17+ ErrorReportingUtility, ScriptRequest)
18 from canonical.launchpad.webapp.interfaces import NotFoundError
19 from lp.soyuz.interfaces.archive import ArchivePurpose, IArchiveSet
20 from lp.registry.interfaces.distribution import IDistributionSet
21@@ -244,11 +248,15 @@
22 for queue_item in queue_items:
23 try:
24 queue_item.realiseUpload(self.logger)
25- except:
26- self.logger.error(
27- "Failure processing queue_item %d" % (
28- queue_item.id), exc_info=True)
29- raise
30+ except Exception:
31+ message = "Failure processing queue_item %d" % (
32+ queue_item.id)
33+ properties = [('error-explanation', message)]
34+ request = ScriptRequest(properties)
35+ error_utility = ErrorReportingUtility()
36+ error_utility.raising(sys.exc_info(), request)
37+ self.logger.error('%s (%s)' % (message,
38+ request.oopsid))
39 else:
40 processed_queue_ids.append(queue_item.id)
41
42
43=== modified file 'lib/lp/soyuz/tests/test_processaccepted.py'
44--- lib/lp/soyuz/tests/test_processaccepted.py 2010-02-23 10:30:56 +0000
45+++ lib/lp/soyuz/tests/test_processaccepted.py 2010-04-13 13:58:19 +0000
46@@ -3,13 +3,14 @@
47
48 """Test process-accepted.py"""
49
50-from zope.component import getUtility
51+from cStringIO import StringIO
52
53 from canonical.config import config
54 from canonical.launchpad.scripts import QuietFakeLogger
55+from canonical.launchpad.webapp.errorlog import ErrorReportingUtility
56 from canonical.testing import LaunchpadZopelessLayer
57
58-from lp.registry.interfaces.distribution import IDistributionSet
59+from lp.registry.interfaces.series import SeriesStatus
60 from lp.soyuz.interfaces.archive import ArchivePurpose
61 from lp.soyuz.interfaces.publishing import PackagePublishingStatus
62 from lp.soyuz.scripts.processaccepted import ProcessAccepted
63@@ -28,34 +29,75 @@
64 self.stp = SoyuzTestPublisher()
65 self.stp.prepareBreezyAutotest()
66 self.test_package_name = "accept-test"
67+ self.distro = self.factory.makeDistribution()
68
69 def getScript(self, test_args=None):
70 """Return a ProcessAccepted instance."""
71 if test_args is None:
72 test_args = []
73- test_args.append(self.stp.ubuntutest.name)
74+ test_args.append(self.distro.name)
75 script = ProcessAccepted("process accepted", test_args=test_args)
76 script.logger = QuietFakeLogger()
77 script.txn = self.layer.txn
78 return script
79
80- def createWaitingAcceptancePackage(self, archive=None):
81+ def createWaitingAcceptancePackage(self, distroseries, archive=None,
82+ sourcename=None):
83 """Create some pending publications."""
84 if archive is None:
85- archive = getUtility(
86- IDistributionSet).getByName('ubuntu').main_archive
87+ archive = self.distro.main_archive
88+ if sourcename is None:
89+ sourcename = self.test_package_name
90 return self.stp.getPubSource(
91- archive=archive, sourcename=self.test_package_name, spr_only=True)
92-
93- def testAcceptCopyArchives(self):
94+ archive=archive, sourcename=sourcename, distroseries=distroseries,
95+ spr_only=True)
96+
97+ def test_robustness(self):
98+ """Test that a broken package doesn't block the publication of other
99+ packages."""
100+ # Attempt to upload one source to a supported series
101+ # The record is created first and then the status of the series
102+ # is changed from DEVELOPMENT to SUPPORTED, otherwise it's impossible
103+ # to create the record
104+ distroseries = self.factory.makeDistroSeries(distribution=self.distro)
105+ broken_source = self.createWaitingAcceptancePackage(
106+ distroseries=distroseries, sourcename="notaccepted")
107+ distroseries.status = SeriesStatus.SUPPORTED
108+ # Also upload some other things
109+ other_distroseries = self.factory.makeDistroSeries(
110+ distribution=self.distro)
111+ other_source = self.createWaitingAcceptancePackage(
112+ distroseries=other_distroseries)
113+ script = self.getScript([])
114+ self.layer.txn.commit()
115+ self.layer.switchDbUser(self.dbuser)
116+ script.main()
117+
118+ # The other source should be published now
119+ published_main = self.distro.main_archive.getPublishedSources(
120+ name=self.test_package_name)
121+ self.assertEqual(published_main.count(), 1)
122+
123+ # And an oops should be filed for the first
124+ error_utility = ErrorReportingUtility()
125+ error_report = error_utility.getLastOopsReport()
126+ fp = StringIO()
127+ error_report.write(fp)
128+ error_text = fp.getvalue()
129+ expected_error = "error-explanation=Failure processing queue_item"
130+ self.assertTrue(expected_error in error_text)
131+
132+ def test_accept_copy_archives(self):
133 """Test that publications in a copy archive are accepted properly."""
134 # Upload some pending packages in a copy archive.
135+ distroseries = self.factory.makeDistroSeries(distribution=self.distro)
136 copy_archive = self.factory.makeArchive(
137- distribution=self.stp.ubuntutest, purpose=ArchivePurpose.COPY)
138+ distribution=self.distro, purpose=ArchivePurpose.COPY)
139 copy_source = self.createWaitingAcceptancePackage(
140- archive=copy_archive)
141+ archive=copy_archive, distroseries=distroseries)
142 # Also upload some stuff in the main archive.
143- main_source = self.createWaitingAcceptancePackage()
144+ main_source = self.createWaitingAcceptancePackage(
145+ distroseries=distroseries)
146
147 # Before accepting, the package should not be published at all.
148 published_copy = copy_archive.getPublishedSources(
149@@ -72,7 +114,7 @@
150 script.main()
151
152 # Packages in main archive should not be accepted and published.
153- published_main = self.stp.ubuntutest.main_archive.getPublishedSources(
154+ published_main = self.distro.main_archive.getPublishedSources(
155 name=self.test_package_name)
156 self.assertEqual(published_main.count(), 0)
157