Merge ~cjwatson/launchpad:librarian-gc-log-delete-failures into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: f88ec60e1d0f4a89ce6be88c5300f35cfa515f74
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:librarian-gc-log-delete-failures
Merge into: launchpad:master
Diff against target: 78 lines (+33/-5)
2 files modified
lib/lp/services/librarianserver/librariangc.py (+9/-5)
lib/lp/services/librarianserver/tests/test_gc.py (+24/-0)
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Review via email: mp+414421@code.launchpad.net

Commit message

Make librarian GC log delete failures rather than crashing

Description of the change

librarian-gc has been crashing on every run since at least the start of 2022. A debug run showed that most of the deletions it was attempting from Swift were succeeding, but occasionally one timed out. Since future runs will retry the deletion, it makes sense to log such events rather than crashing.

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

Nice fix with good comments in unit test!

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/librarianserver/librariangc.py b/lib/lp/services/librarianserver/librariangc.py
index aa3429f..26b0462 100644
--- a/lib/lp/services/librarianserver/librariangc.py
+++ b/lib/lp/services/librarianserver/librariangc.py
@@ -553,7 +553,9 @@ class UnreferencedContentPruner:
553 'Swift {}'.format(connection_pool.os_auth_url))553 'Swift {}'.format(connection_pool.os_auth_url))
554 except swiftclient.ClientException as x:554 except swiftclient.ClientException as x:
555 if x.http_status != 404:555 if x.http_status != 404:
556 raise556 log.exception(
557 "Failed to delete (%s, %s) from Swift (%s)",
558 container, name, connection_pool.os_auth_url)
557559
558 if removed:560 if removed:
559 log.debug3(561 log.debug3(
@@ -868,12 +870,14 @@ def delete_unwanted_swift_files(con):
868 with swift.connection(connection_pool) as swift_connection:870 with swift.connection(connection_pool) as swift_connection:
869 try:871 try:
870 swift_connection.delete_object(container, name)872 swift_connection.delete_object(container, name)
873 log.debug3(
874 'Deleted (%s, %s) from Swift (%s)',
875 container, name, connection_pool.os_auth_url)
871 except swiftclient.ClientException as e:876 except swiftclient.ClientException as e:
872 if e.http_status != 404:877 if e.http_status != 404:
873 raise878 log.exception(
874 log.debug3(879 "Failed to delete (%s, %s) from Swift (%s)",
875 'Deleted (%s, %s) from Swift (%s)',880 container, name, connection_pool.os_auth_url)
876 container, name, connection_pool.os_auth_url)
877 removed_count += 1881 removed_count += 1
878882
879 if next_wanted_content_id == content_id:883 if next_wanted_content_id == content_id:
diff --git a/lib/lp/services/librarianserver/tests/test_gc.py b/lib/lp/services/librarianserver/tests/test_gc.py
index 716bfa3..7e1eedb 100644
--- a/lib/lp/services/librarianserver/tests/test_gc.py
+++ b/lib/lp/services/librarianserver/tests/test_gc.py
@@ -27,8 +27,10 @@ from six.moves.urllib.parse import urljoin
27from storm.store import Store27from storm.store import Store
28from swiftclient import client as swiftclient28from swiftclient import client as swiftclient
29from testtools.matchers import (29from testtools.matchers import (
30 AnyMatch,
30 Equals,31 Equals,
31 MatchesListwise,32 MatchesListwise,
33 MatchesRegex,
32 )34 )
33import transaction35import transaction
3436
@@ -759,6 +761,28 @@ class TestSwiftLibrarianGarbageCollection(
759 if x.http_status != 404:761 if x.http_status != 404:
760 raise762 raise
761763
764 def test_DeleteUnreferencedContent_handles_timeout(self):
765 # If delete_unreferenced_content times out trying to delete a file
766 # from Swift, it logs an error and moves on.
767
768 # Merge the duplicates. This creates an
769 # unreferenced LibraryFileContent.
770 librariangc.merge_duplicates(self.con)
771
772 # Force a timeout from the Swift fixture.
773 self.pushConfig(
774 'librarian_server', os_username='timeout', swift_timeout=0.1)
775 swift.reconfigure_connection_pools()
776
777 # Delete unreferenced content.
778 librariangc.delete_unreferenced_content(self.con)
779
780 # We logged an error message.
781 self.assertThat(
782 librariangc.log.getLogBuffer().splitlines(),
783 AnyMatch(
784 MatchesRegex(r'^ERROR Failed to delete .* from Swift .*')))
785
762 def test_delete_unwanted_files_handles_segments(self):786 def test_delete_unwanted_files_handles_segments(self):
763 # Large files are handled by Swift as multiple segments joined787 # Large files are handled by Swift as multiple segments joined
764 # by a manifest. GC treats the segments like the original file.788 # by a manifest. GC treats the segments like the original file.

Subscribers

People subscribed via source and target branches

to status/vote changes: