Merge ~cjwatson/launchpad:pool-file-overwrite-error-enormous-oopses into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 47e9a7e9a1717ba2f40e9fe3e01924d7418b46da
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:pool-file-overwrite-error-enormous-oopses
Merge into: launchpad:master
Diff against target: 105 lines (+41/-2)
4 files modified
lib/lp/services/timeline/requesttimeline.py (+20/-0)
lib/lp/services/timeline/tests/test_requesttimeline.py (+14/-0)
lib/lp/soyuz/model/publishing.py (+3/-1)
lib/lp/soyuz/tests/test_publishing.py (+4/-1)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Review via email: mp+436331@code.launchpad.net

Commit message

Suppress timeline in PoolFileOverwriteError OOPSes

Description of the change

The traceback for `PoolFileOverwriteError` (raised when the publisher attempts to overwrite an existing file in a pool with different content) tells us everything we need to know: we get both of the checksums and the target path.

However, the OOPSes also contain an enormous timeline mainly consisting of every SQL statement the publisher has issued as part of processing that archive. These timelines tend to cause the OOPS processing system to back up, and provide essentially no information of any value. Instead, just arrange for these OOPSes to be raised with a temporary empty timeline.

To post a comment you must log in.
Revision history for this message
Guruprasad (lgp171188) wrote :

LGTM 👍

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/services/timeline/requesttimeline.py b/lib/lp/services/timeline/requesttimeline.py
index 0c1460c..7fb0332 100644
--- a/lib/lp/services/timeline/requesttimeline.py
+++ b/lib/lp/services/timeline/requesttimeline.py
@@ -6,8 +6,11 @@
6__all__ = [6__all__ = [
7 "get_request_timeline",7 "get_request_timeline",
8 "set_request_timeline",8 "set_request_timeline",
9 "temporary_request_timeline",
9]10]
1011
12from contextlib import contextmanager
13
11from timeline import Timeline14from timeline import Timeline
1215
13# XXX RobertCollins 2010-09-01 bug=623199: Undesirable but pragmatic.16# XXX RobertCollins 2010-09-01 bug=623199: Undesirable but pragmatic.
@@ -48,3 +51,20 @@ def set_request_timeline(request, timeline):
48 return timeline51 return timeline
49 # Disabled code path: bug 623199, ideally we would use this code path.52 # Disabled code path: bug 623199, ideally we would use this code path.
50 request.annotations["timeline"] = timeline53 request.annotations["timeline"] = timeline
54
55
56@contextmanager
57def temporary_request_timeline(request):
58 """Give `request` a temporary timeline.
59
60 This is useful in contexts where we want to raise an OOPS but we know
61 that the timeline is uninteresting and may be very large.
62
63 :param request: A Zope/Launchpad request object.
64 """
65 old_timeline = get_request_timeline(request)
66 try:
67 set_request_timeline(request, Timeline())
68 yield
69 finally:
70 set_request_timeline(request, old_timeline)
diff --git a/lib/lp/services/timeline/tests/test_requesttimeline.py b/lib/lp/services/timeline/tests/test_requesttimeline.py
index 341ce37..a49ba8a 100644
--- a/lib/lp/services/timeline/tests/test_requesttimeline.py
+++ b/lib/lp/services/timeline/tests/test_requesttimeline.py
@@ -11,6 +11,7 @@ from lp.services import webapp
11from lp.services.timeline.requesttimeline import (11from lp.services.timeline.requesttimeline import (
12 get_request_timeline,12 get_request_timeline,
13 set_request_timeline,13 set_request_timeline,
14 temporary_request_timeline,
14)15)
1516
1617
@@ -55,3 +56,16 @@ class TestRequestTimeline(testtools.TestCase):
55 self.assertEqual(timeline, get_request_timeline(req))56 self.assertEqual(timeline, get_request_timeline(req))
5657
57 # Tests while adapter._local contains the timeline ---end---58 # Tests while adapter._local contains the timeline ---end---
59
60 def test_temporary_request_timeline(self):
61 req = TestRequest()
62 timeline = Timeline()
63 set_request_timeline(req, timeline)
64 timeline.start("test", "test").finish()
65 self.assertEqual(timeline, get_request_timeline(req))
66 self.assertEqual(1, len(timeline.actions))
67 with temporary_request_timeline(req):
68 self.assertNotEqual(timeline, get_request_timeline(req))
69 get_request_timeline(req).start("test-2", "test-2").finish()
70 self.assertEqual(timeline, get_request_timeline(req))
71 self.assertEqual(1, len(timeline.actions))
diff --git a/lib/lp/soyuz/model/publishing.py b/lib/lp/soyuz/model/publishing.py
index b2f7a9d..82eea43 100644
--- a/lib/lp/soyuz/model/publishing.py
+++ b/lib/lp/soyuz/model/publishing.py
@@ -50,6 +50,7 @@ from lp.services.database.stormexpr import IsDistinctFrom
50from lp.services.librarian.browser import ProxiedLibraryFileAlias50from lp.services.librarian.browser import ProxiedLibraryFileAlias
51from lp.services.librarian.model import LibraryFileAlias, LibraryFileContent51from lp.services.librarian.model import LibraryFileAlias, LibraryFileContent
52from lp.services.propertycache import cachedproperty, get_property_cache52from lp.services.propertycache import cachedproperty, get_property_cache
53from lp.services.timeline.requesttimeline import temporary_request_timeline
53from lp.services.webapp.errorlog import ErrorReportingUtility, ScriptRequest54from lp.services.webapp.errorlog import ErrorReportingUtility, ScriptRequest
54from lp.services.worlddata.model.country import Country55from lp.services.worlddata.model.country import Country
55from lp.soyuz.adapters.proxiedsourcefiles import ProxiedSourceLibraryFileAlias56from lp.soyuz.adapters.proxiedsourcefiles import ProxiedSourceLibraryFileAlias
@@ -190,7 +191,8 @@ class ArchivePublisherBase:
190 properties = [("error-explanation", message)]191 properties = [("error-explanation", message)]
191 request = ScriptRequest(properties)192 request = ScriptRequest(properties)
192 error_utility = ErrorReportingUtility()193 error_utility = ErrorReportingUtility()
193 error_utility.raising(sys.exc_info(), request)194 with temporary_request_timeline(request):
195 error_utility.raising(sys.exc_info(), request)
194 log.error("%s (%s)" % (message, request.oopsid))196 log.error("%s (%s)" % (message, request.oopsid))
195 else:197 else:
196 self.setPublished()198 self.setPublished()
diff --git a/lib/lp/soyuz/tests/test_publishing.py b/lib/lp/soyuz/tests/test_publishing.py
index d2e041c..7812578 100644
--- a/lib/lp/soyuz/tests/test_publishing.py
+++ b/lib/lp/soyuz/tests/test_publishing.py
@@ -994,8 +994,11 @@ class TestNativePublishing(TestNativePublishingBase):
994 pub_source = self.getPubSource(filecontent=b"Something")994 pub_source = self.getPubSource(filecontent=b"Something")
995 pub_source.publish(self.disk_pool, self.logger)995 pub_source.publish(self.disk_pool, self.logger)
996996
997 # And an oops should be filed for the error.997 # An oops should be filed for the error, but we don't include the
998 # SQL timeline; it may be very large and tells us nothing that we
999 # can't get from the error message.
998 self.assertEqual("PoolFileOverwriteError", self.oopses[0]["type"])1000 self.assertEqual("PoolFileOverwriteError", self.oopses[0]["type"])
1001 self.assertEqual([], self.oopses[0]["timeline"])
9991002
1000 self.layer.commit()1003 self.layer.commit()
1001 self.assertEqual(pub_source.status, PackagePublishingStatus.PENDING)1004 self.assertEqual(pub_source.status, PackagePublishingStatus.PENDING)

Subscribers

People subscribed via source and target branches

to status/vote changes: