Skip to content

Commit fccfb43

Browse files
[fix] Distinguish client cancellation from server errors during slice upload (#290)
1 parent f36e18d commit fccfb43

16 files changed

Lines changed: 846 additions & 80 deletions

File tree

src/ByteSync.Client/Interfaces/Controls/Communications/IAdaptiveUploadController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using ByteSync.Common.Business.Communications.Transfers;
2+
13
namespace ByteSync.Interfaces.Controls.Communications;
24

35
public interface IAdaptiveUploadController
@@ -8,6 +10,5 @@ public interface IAdaptiveUploadController
810

911
int GetNextChunkSizeBytes();
1012

11-
void RecordUploadResult(TimeSpan elapsed, bool isSuccess, int partNumber, int? statusCode = null,
12-
Exception? exception = null, string? fileId = null, long actualBytes = -1);
13+
void RecordUploadResult(UploadResult uploadResult);
1314
}

src/ByteSync.Client/Services/Communications/Transfers/Strategies/AzureBlobStorageUploadStrategy.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public async Task<UploadFileResponse> UploadAsync(FileUploaderSlice slice, FileS
2727
var blob = new BlobClient(new Uri(storageLocation.Url), options);
2828
var response = await blob.UploadAsync(slice.MemoryStream, cancellationToken);
2929

30-
_logger.LogDebug("UploadAvailableSlice: slice {number} is uploaded", slice.PartNumber);
30+
_logger.LogDebug("UploadAvailableSlice: slice {PartNumber} is uploaded", slice.PartNumber);
3131

3232
var rawResponse = response.GetRawResponse();
3333

@@ -45,10 +45,15 @@ public async Task<UploadFileResponse> UploadAsync(FileUploaderSlice slice, FileS
4545
);
4646
}
4747
}
48+
catch (OperationCanceledException ex)
49+
{
50+
_logger.LogWarning(ex, "Upload of slice {PartNumber} was canceled or timed out", slice.PartNumber);
51+
return UploadFailureClassifier.Classify(ex, cancellationToken);
52+
}
4853
catch (Exception ex)
4954
{
50-
_logger.LogError(ex, "Failed to upload slice {number}", slice.PartNumber);
51-
return UploadFileResponse.Failure(500, ex);
55+
_logger.LogError(ex, "Failed to upload slice {PartNumber}", slice.PartNumber);
56+
return UploadFailureClassifier.Classify(ex, cancellationToken);
5257
}
5358
}
5459
}

src/ByteSync.Client/Services/Communications/Transfers/Strategies/CloudflareR2UploadStrategy.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,15 @@ public async Task<UploadFileResponse> UploadAsync(FileUploaderSlice slice, FileS
7676
);
7777
}
7878
}
79+
catch (OperationCanceledException ex)
80+
{
81+
_logger.LogWarning(ex, "Upload of slice {PartNumber} was canceled or timed out", slice.PartNumber);
82+
return UploadFailureClassifier.Classify(ex, cancellationToken);
83+
}
7984
catch (Exception ex)
8085
{
81-
_logger.LogError(ex, "Failed to upload slice {number}", slice.PartNumber);
82-
return UploadFileResponse.Failure(500, ex);
86+
_logger.LogError(ex, "Failed to upload slice {PartNumber}", slice.PartNumber);
87+
return UploadFailureClassifier.Classify(ex, cancellationToken);
8388
}
8489
}
8590
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Threading;
3+
using ByteSync.Common.Business.Communications.Transfers;
4+
5+
namespace ByteSync.Services.Communications.Transfers.Strategies;
6+
7+
public static class UploadFailureClassifier
8+
{
9+
public static UploadFileResponse Classify(Exception exception, CancellationToken cancellationToken)
10+
{
11+
if (exception is OperationCanceledException && cancellationToken.IsCancellationRequested)
12+
{
13+
return UploadFileResponse.ClientCancellation(exception);
14+
}
15+
16+
if (exception is OperationCanceledException)
17+
{
18+
return UploadFileResponse.ClientTimeout(exception);
19+
}
20+
21+
return UploadFileResponse.Failure(500, exception);
22+
}
23+
}

src/ByteSync.Client/Services/Communications/Transfers/Uploading/AdaptiveUploadController.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Reactive.Linq;
22
using ByteSync.Business.Sessions;
3+
using ByteSync.Common.Business.Communications.Transfers;
34
using ByteSync.Interfaces.Controls.Communications;
45
using ByteSync.Interfaces.Services.Sessions;
56

@@ -81,14 +82,18 @@ public int GetNextChunkSizeBytes()
8182
}
8283
}
8384

84-
public void RecordUploadResult(TimeSpan elapsed, bool isSuccess, int partNumber, int? statusCode = null,
85-
Exception? exception = null, string? fileId = null, long actualBytes = -1)
85+
public void RecordUploadResult(UploadResult uploadResult)
8686
{
8787
lock (_syncRoot)
8888
{
89-
EnqueueSample(elapsed, isSuccess, actualBytes);
89+
if (IsClientSideFailure(uploadResult.FailureKind))
90+
{
91+
return;
92+
}
93+
94+
EnqueueSample(uploadResult.Elapsed, uploadResult.IsSuccess, uploadResult.ActualBytes);
9095

91-
if (HandleBandwidthReset(isSuccess, statusCode))
96+
if (HandleBandwidthReset(uploadResult.IsSuccess, uploadResult.StatusCode))
9297
{
9398
return;
9499
}
@@ -102,18 +107,18 @@ public void RecordUploadResult(TimeSpan elapsed, bool isSuccess, int partNumber,
102107

103108
_logger.LogDebug(
104109
"Adaptive: file {FileId} maxElapsed={MaxElapsedMs} ms, window={Window}, parallelism={Parallelism}, chunkSize={ChunkKb} KB",
105-
fileId ?? "-",
110+
uploadResult.FileId ?? "-",
106111
maxElapsed.TotalMilliseconds,
107112
_windowSize,
108113
_currentParallelism,
109114
Math.Round(_currentChunkSizeBytes / 1024d));
110115

111-
if (TryHandleDownscale(maxElapsed, fileId))
116+
if (TryHandleDownscale(maxElapsed, uploadResult.FileId))
112117
{
113118
return;
114119
}
115120

116-
TryHandleUpscale(fileId);
121+
TryHandleUpscale(uploadResult.FileId);
117122
}
118123
}
119124

@@ -146,6 +151,11 @@ private void EnqueueSample(TimeSpan elapsed, bool isSuccess, long actualBytes)
146151
}
147152
}
148153

154+
private static bool IsClientSideFailure(UploadFailureKind failureKind)
155+
{
156+
return failureKind is UploadFailureKind.ClientCancellation or UploadFailureKind.ClientTimeout;
157+
}
158+
149159
private bool HandleBandwidthReset(bool isSuccess, int? statusCode)
150160
{
151161
if (!isSuccess && statusCode != null)
@@ -278,7 +288,7 @@ private void TryHandleUpscale(string? fileId)
278288
}
279289
}
280290

281-
private double GetUpscaleMultiplier(TimeSpan maxElapsedEligible)
291+
private static double GetUpscaleMultiplier(TimeSpan maxElapsedEligible)
282292
{
283293
if (maxElapsedEligible < TimeSpan.FromSeconds(1))
284294
{

0 commit comments

Comments
 (0)