|
13 | 13 | ClientAuthenticationError, |
14 | 14 | HttpResponseError, |
15 | 15 | ResourceExistsError, |
16 | | - ServiceResponseError |
| 16 | + ServiceResponseError, |
| 17 | + ServiceResponseTimeoutError |
17 | 18 | ) |
18 | 19 | from azure.core.pipeline.transport import RequestsTransport |
19 | 20 | from azure.storage.blob._shared.authentication import AzureSigningError |
@@ -639,4 +640,51 @@ def assert_exception_retry_hook(**kwargs): |
639 | 640 |
|
640 | 641 | assert retry_counter.count == 3 |
641 | 642 |
|
| 643 | + @BlobPreparer() |
| 644 | + @recorded_by_proxy |
| 645 | + def test_retry_on_service_response_error(self, **kwargs): |
| 646 | + storage_account_name = kwargs.pop("storage_account_name") |
| 647 | + storage_account_key = kwargs.pop("storage_account_key") |
| 648 | + |
| 649 | + # Arrange |
| 650 | + container_name = self.get_resource_name('utcontainer') |
| 651 | + blob_name = self.get_resource_name('blob') |
| 652 | + service = self._create_storage_service( |
| 653 | + BlobServiceClient, storage_account_name, storage_account_key, max_block_size=4) |
| 654 | + container = service.create_container(container_name) |
| 655 | + data = b'abcd' * 4 |
| 656 | + container.upload_blob(blob_name, data, overwrite=True) |
| 657 | + |
| 658 | + retry = LinearRetry(backoff=1, random_jitter_range=1) |
| 659 | + retry_counter = RetryCounter() |
| 660 | + retry_service = self._create_storage_service( |
| 661 | + BlobServiceClient, |
| 662 | + storage_account_name, |
| 663 | + storage_account_key, |
| 664 | + retry_policy=retry, |
| 665 | + max_block_size=4 |
| 666 | + ) |
| 667 | + blob = retry_service.get_blob_client(container_name, blob_name) |
| 668 | + |
| 669 | + # Mock the internal response to raise ServiceResponseError on first chunk processing |
| 670 | + from azure.storage.blob._download import process_content as real_process_content |
| 671 | + |
| 672 | + def mock_process_content_with_error(response, start_offset, end_offset, encryption): |
| 673 | + retry_counter.simple_count(retry) |
| 674 | + conn_error = AzureError("Connection reset by peer") |
| 675 | + if retry_counter.count == 1: |
| 676 | + raise ServiceResponseError(conn_error, error=conn_error) |
| 677 | + elif retry_counter.count == 2: |
| 678 | + raise ServiceResponseTimeoutError(conn_error, error=conn_error) |
| 679 | + return real_process_content(response, start_offset, end_offset, encryption) |
| 680 | + |
| 681 | + # Act |
| 682 | + try: |
| 683 | + with mock.patch('azure.storage.blob._download.process_content', side_effect=mock_process_content_with_error): |
| 684 | + downloaded_data = blob.download_blob().readall() |
| 685 | + assert downloaded_data == data |
| 686 | + assert retry_counter.count >= 3 |
| 687 | + finally: |
| 688 | + service.delete_container(container_name) |
| 689 | + |
642 | 690 | # ------------------------------------------------------------------------------ |
0 commit comments