diff --git a/amber/src/main/python/pytexera/storage/large_binary_output_stream.py b/amber/src/main/python/pytexera/storage/large_binary_output_stream.py index 0cdf8a3679f..0a47a853cb3 100644 --- a/amber/src/main/python/pytexera/storage/large_binary_output_stream.py +++ b/amber/src/main/python/pytexera/storage/large_binary_output_stream.py @@ -153,12 +153,20 @@ def write(self, b: Union[bytes, bytearray]) -> int: if self._upload_thread is None: def upload_worker(): + s3 = None try: large_binary_manager._ensure_bucket_exists(self._bucket_name) s3 = large_binary_manager._get_s3_client() reader = _QueueReader(self._queue) s3.upload_fileobj(reader, self._bucket_name, self._object_key) except Exception as e: + if s3 is not None: + try: + s3.delete_object( + Bucket=self._bucket_name, Key=self._object_key + ) + except Exception: + pass with self._lock: self._upload_exception = e finally: @@ -214,12 +222,10 @@ def close(self) -> None: self._upload_thread.join() self._upload_complete.wait() - # Check for errors and cleanup if needed with self._lock: exception = self._upload_exception if exception is not None: - self._cleanup_failed_upload() raise IOError( f"Failed to complete upload: {exception}" ) from exception @@ -228,15 +234,6 @@ def close(self) -> None: # the second close() call on Python 3.13+. super().close() - def _cleanup_failed_upload(self): - """Clean up a failed upload by deleting the S3 object.""" - try: - s3 = large_binary_manager._get_s3_client() - s3.delete_object(Bucket=self._bucket_name, Key=self._object_key) - except Exception: - # Ignore cleanup errors - we're already handling an upload failure - pass - def __enter__(self): """Context manager entry.""" return self diff --git a/amber/src/test/python/pytexera/storage/test_large_binary_output_stream.py b/amber/src/test/python/pytexera/storage/test_large_binary_output_stream.py index 17725d9c66a..5f71f4b82ca 100644 --- a/amber/src/test/python/pytexera/storage/test_large_binary_output_stream.py +++ b/amber/src/test/python/pytexera/storage/test_large_binary_output_stream.py @@ -249,7 +249,7 @@ def test_multiple_close_calls(self, large_binary): class TestCleanupFailedUpload: - """Direct unit tests for _cleanup_failed_upload's silent-swallow path.""" + """Direct unit tests for the upload worker's silent-swallow cleanup.""" @pytest.fixture def large_binary(self):