public Task <BlobIdentifierWithBlocks> UploadLogToBlobStore(Stream blob, string hubName, Guid planId, int logId) { var blockBlobId = VsoHash.CalculateBlobIdentifierWithBlocks(blob); blob.Position = 0; using (var reader = new StreamReader(blob)) { var text = reader.ReadToEnd(); var lines = text.Split("\n"); UploadedLogBlobs.Add(blockBlobId, lines); } return(Task.FromResult(blockBlobId)); }
/// <summary> /// Alternative for UploadAndReferenceBlobAsync that uses WalkBlocksAsync instead of the synchronous WalkBlocks. /// Also utilizes the AsyncHttpRetryHelper to mitigate transient exceptions. /// </summary> public static Task UploadAndReferenceBlobWithRetriesAsync( this IBlobStoreHttpClient client, BlobIdentifier blobId, Stream stream, BlobReference reference, Context context, CancellationToken cts) { Contract.Requires(stream != null); var attempt = 0; return(AsyncHttpRetryHelper.InvokeVoidAsync( async() => { bool blobUploaded = false; stream.Position = 0; attempt++; await VsoHash.WalkBlocksAsync( stream, blockActionSemaphore: null, multiBlocksInParallel: true, singleBlockCallback: async(block, blockLength, blockHash) => { await client.PutSingleBlockBlobAndReferenceAsync( blobId, block, blockLength, reference, cts).ConfigureAwait(false); blobUploaded = true; }, multiBlockCallback: (block, blockLength, blockHash, isFinalBlock) => client.PutBlobBlockAsync(blobId, block, blockLength, cts), multiBlockSealCallback: async blobIdWithBlocks => { var failedRefs = await client.TryReferenceWithBlocksAsync( new Dictionary <BlobIdentifierWithBlocks, IEnumerable <BlobReference> > { { blobIdWithBlocks, new[] { reference } } }, cancellationToken: cts).ConfigureAwait(false); blobUploaded = !failedRefs.Any(); } ); if (!blobUploaded) { throw new AsyncHttpRetryHelper.RetryableException($"Could not upload blob on attempt {attempt}."); } }, maxRetries: 5, tracer: new AppTraceSourceContextAdapter(context, "BlobStoreHttpClient", SourceLevels.All), canRetryDelegate: exception => { // HACK HACK: This is an additional layer of retries specifically to catch the SSL exceptions seen in DM. // Newer versions of Artifact packages have this retry automatically, but the packages deployed with the M119.0 release do not. // Once the next release is completed, these retries can be removed. if (exception is HttpRequestException && exception.InnerException is WebException) { return true; } while (exception != null) { if (exception is TimeoutException) { return true; } exception = exception.InnerException; } return false; }, cancellationToken: cts, continueOnCapturedContext: false, context: context.Id.ToString())); }