diff --git a/sdk/storage/storage-blob/CHANGELOG.md b/sdk/storage/storage-blob/CHANGELOG.md index 04b0424449e3..8295834beea1 100644 --- a/sdk/storage/storage-blob/CHANGELOG.md +++ b/sdk/storage/storage-blob/CHANGELOG.md @@ -6,6 +6,10 @@ - Added support for service version 2021-10-04. +### Bugs Fixed + +- Fixed a hang issue in BlobClient.downloadToBuffer when encountering transient network failure. + ## 12.11.0 (2022-07-08) ### Features Added diff --git a/sdk/storage/storage-blob/src/utils/constants.ts b/sdk/storage/storage-blob/src/utils/constants.ts index d315608c3437..fa3ab3e1fe1f 100644 --- a/sdk/storage/storage-blob/src/utils/constants.ts +++ b/sdk/storage/storage-blob/src/utils/constants.ts @@ -10,6 +10,8 @@ export const BLOCK_BLOB_MAX_BLOCKS: number = 50000; export const DEFAULT_BLOCK_BUFFER_SIZE_BYTES: number = 8 * 1024 * 1024; // 8MB export const DEFAULT_BLOB_DOWNLOAD_BLOCK_BYTES: number = 4 * 1024 * 1024; // 4MB export const DEFAULT_MAX_DOWNLOAD_RETRY_REQUESTS: number = 5; + +export const REQUEST_TIMEOUT: number = 100 * 1000; // In ms /** * The OAuth scope to use with Azure Storage. */ diff --git a/sdk/storage/storage-blob/src/utils/utils.node.ts b/sdk/storage/storage-blob/src/utils/utils.node.ts index 2ca67292ab65..48e979d6ff15 100644 --- a/sdk/storage/storage-blob/src/utils/utils.node.ts +++ b/sdk/storage/storage-blob/src/utils/utils.node.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import * as util from "util"; +import { REQUEST_TIMEOUT } from "./constants"; /** * Reads a readable stream into buffer. Fill the buffer from offset to end. @@ -24,8 +25,14 @@ export async function streamToBuffer( const count = end - offset; // Total amount of data needed in stream return new Promise((resolve, reject) => { + const timeout = setTimeout( + () => reject(new Error(`The operation cannot be completed in timeout.`)), + REQUEST_TIMEOUT + ); + stream.on("readable", () => { if (pos >= count) { + clearTimeout(timeout); resolve(); return; } @@ -46,6 +53,7 @@ export async function streamToBuffer( }); stream.on("end", () => { + clearTimeout(timeout); if (pos < count) { reject( new Error( @@ -56,7 +64,10 @@ export async function streamToBuffer( resolve(); }); - stream.on("error", reject); + stream.on("error", (msg) => { + clearTimeout(timeout); + reject(msg); + }); }); } diff --git a/sdk/storage/storage-file-share/CHANGELOG.md b/sdk/storage/storage-file-share/CHANGELOG.md index 009f9aba5a36..16539d95a8ef 100644 --- a/sdk/storage/storage-file-share/CHANGELOG.md +++ b/sdk/storage/storage-file-share/CHANGELOG.md @@ -8,6 +8,8 @@ ### Bugs Fixed +- Fixed a hang issue in ShareFileClient.downloadToBuffer when encountering transient network failure. + ### Other Changes ## 12.11.0 (2022-07-08) diff --git a/sdk/storage/storage-file-share/src/utils/constants.ts b/sdk/storage/storage-file-share/src/utils/constants.ts index aa15fb14e1e2..0018e2f39a34 100644 --- a/sdk/storage/storage-file-share/src/utils/constants.ts +++ b/sdk/storage/storage-file-share/src/utils/constants.ts @@ -8,6 +8,7 @@ export const FILE_MAX_SIZE_BYTES: number = 4 * 1024 * 1024 * 1024 * 1024; // 4TB export const FILE_RANGE_MAX_SIZE_BYTES: number = 4 * 1024 * 1024; // 4MB export const DEFAULT_MAX_DOWNLOAD_RETRY_REQUESTS: number = 5; export const DEFAULT_HIGH_LEVEL_CONCURRENCY: number = 5; +export const REQUEST_TIMEOUT: number = 100 * 1000; // In ms export const URLConstants = { Parameters: { diff --git a/sdk/storage/storage-file-share/src/utils/utils.node.ts b/sdk/storage/storage-file-share/src/utils/utils.node.ts index 547cca0fbcc4..0c25c7f10b2d 100644 --- a/sdk/storage/storage-file-share/src/utils/utils.node.ts +++ b/sdk/storage/storage-file-share/src/utils/utils.node.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import * as util from "util"; +import { REQUEST_TIMEOUT } from "./constants"; /** * Reads a readable stream into buffer. Fill the buffer from offset to end. @@ -24,8 +25,13 @@ export async function streamToBuffer( const count = end - offset; // Total amount of data needed in stream return new Promise((resolve, reject) => { + const timeout = setTimeout( + () => reject(new Error(`The operation cannot be completed in timeout.`)), + REQUEST_TIMEOUT + ); stream.on("readable", () => { if (pos >= count) { + clearTimeout(timeout); resolve(); return; } @@ -46,6 +52,7 @@ export async function streamToBuffer( }); stream.on("end", () => { + clearTimeout(timeout); if (pos < count) { reject( new Error( @@ -56,7 +63,10 @@ export async function streamToBuffer( resolve(); }); - stream.on("error", reject); + stream.on("error", (msg) => { + clearTimeout(timeout); + reject(msg); + }); }); }