We have 500 machine which upload file at same time. We are getting RateLimitException. We are doing a retry after waiting rateLimitException.ErrorResponse.RetryAfter seconds.
to test this. I came up with a console app.
Following is my code
public async Task UploadDBparallelly(List<string> dbLocalFilesPath)
{
List<Task> tasks = new List<Task>();
foreach (var item in dbLocalFilesPath.Select((value, i) => new { i, value }))
{
string dbLocalPath = item.value;
int index = item.i;
Logger.Instance.LogInfo($"dbLocalPath: {dbLocalPath}");
tasks.Add(Task.Run(async () =>
{
try
{
//var uploadPathWithFileName = GetFilePathWithFileName(dbLocalPath);
// Your console app logic goes here
await Upload(dbLocalPath, GetFilePathWithFileName(dbLocalPath));
}
catch (Exception ex)
{
Logger.Instance.LogError($"Error Exception {ex}");
}
}));
}
try
{
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
// Handle any exceptions thrown by tasks here
Logger.Instance.LogError($"Error Exception {ex}");
}
}
public static async Task Upload(string localPath, string remotePath)
{
try
{
string accessToken = ConfigurationManager.AppSettings["AccessToken"];
using (DropboxClient client = new DropboxClient(accessToken))
{
using (FileStream fileStream = System.IO.File.Open(localPath, FileMode.Open))
{
//Converting bytes to Megabyte
long fileSize = fileStream.Length / 1024 / 1024;
Logger.Instance.LogInfo($"Total File Size of backup file : {fileSize} MB");
//File Should be under 150MB
if (fileSize <= 150)
{
Logger.Instance.LogDebug("started direct upload backup to dropbox");
FilesUserRoutes files = client.Files;
string path = remotePath;
Stream stream = (Stream)fileStream;
DateTime? clientModified = new DateTime?();
Stream body = stream;
FileMetadata fileMetadata = await files.UploadAsync(path, clientModified: clientModified, body: body);
}
else
{
Logger.Instance.LogDebug("started chunk upload backup to dropbox");
const int chunkSize = 4096 * 1024;
await ChunkUpload(remotePath, fileStream, chunkSize, client, localPath);
}
}
}
}
catch (DropboxException dropboxException)
{
if (dropboxException.GetType().Name == typeof(RateLimitException).Name)
{
var rateLimitException = dropboxException as RateLimitException;
Logger.Instance.LogError($"Upload: Rate limit exceeded. Waiting before retrying...");
Logger.Instance.LogError($"Reason: {rateLimitException.ErrorResponse.Reason}: RetryAfter {rateLimitException.ErrorResponse.RetryAfter}");
var backoff = TimeSpan.FromSeconds(rateLimitException.ErrorResponse.RetryAfter);
Thread.Sleep(Convert.ToInt32(rateLimitException.ErrorResponse.RetryAfter) * 1000);
await Upload(localPath, remotePath); // Retry after delay
}
else
{
Logger.Instance.LogError($"dropboxException {dropboxException}");
}
}
catch (Exception ex)
{
Logger.Instance.LogError("Error in upload backup to dropbox", ex);
throw ex;
}
}
private static async Task ChunkUpload(string remotePath, FileStream fileStream, int chunkSize, DropboxClient client, string localPath)
{
try
{
Console.WriteLine($"Chunk upload file...{localPath}");
int numChunks = (int)Math.Ceiling((double)fileStream.Length / chunkSize);
Console.WriteLine($"SnumChunks {numChunks} ");
byte[] buffer = new byte[chunkSize];
string sessionId = null;
for (var idx = 0; idx < numChunks; idx++)
{
Console.WriteLine($"Start uploading chunk {idx} , LocalPath {localPath} ");
var byteRead = fileStream.Read(buffer, 0, chunkSize);
using (MemoryStream memStream = new MemoryStream(buffer, 0, byteRead))
{
if (idx == 0)
{
var result = client.Files.UploadSessionStartAsync(body: memStream).GetAwaiter().GetResult();
sessionId = result.SessionId;
}
else
{
UploadSessionCursor cursor = new UploadSessionCursor(sessionId, (ulong)(chunkSize * idx));
if (idx == numChunks - 1)
{
Logger.Instance.LogInfo($"DONE FOR{localPath}");
await client.Files.UploadSessionFinishAsync(cursor: cursor, commit: new CommitInfo(remotePath), body: memStream);
}
else
{
client.Files.UploadSessionAppendV2Async(cursor, body: memStream).GetAwaiter().GetResult();
}
}
}
}
}
catch (DropboxException dropboxException)
{
fileStream.Dispose();
client.Dispose();
if (dropboxException.GetType().Name == typeof(RateLimitException).Name)
{
var rateLimitException = dropboxException as RateLimitException;
Logger.Instance.LogError($"ChunkUpload: Rate limit exceeded. Waiting before retrying... RETRY FOR{localPath}");
Logger.Instance.LogError($"Reason: {rateLimitException.ErrorResponse.Reason}: RetryAfter {rateLimitException.ErrorResponse.RetryAfter}");
var backoff = TimeSpan.FromSeconds(rateLimitException.ErrorResponse.RetryAfter);
await Task.Delay(Convert.ToInt32(rateLimitException.ErrorResponse.RetryAfter) * 1000);
await Upload(localPath, remotePath); // Retry after delay
}
else
{
Logger.Instance.LogError($"dropboxException {dropboxException}");
}
}
catch (Exception ex)
{
Logger.Instance.LogError($"Error in chunk upload process {remotePath}", ex);
}
finally
{
fileStream.Dispose();
client.Dispose();
}
}
I'm getting following exception. What I might be missing?
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Dropbox.Api.DropboxRequestHandler.<RequestJsonString>d__2f.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Dropbox.Api.DropboxRequestHandler.<RequestJsonStringWithRetry>d__1a.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Dropbox.Api.DropboxRequestHandler.<Dropbox.Api.Stone.ITransport.SendUploadRequestAsync>d__d`3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Odin.Compute.OdinDatabaseBackupManager.DropboxUploadTest.<ChunkUpload>d__9.MoveNext() in C:\Work\AWC\AWC TFS\GIT\The ONE Platform\Source\Odin.Compute.OdinDatabaseBackupManager\DropboxUploadTest.cs:line 179