mirror of
https://github.com/abraunegg/onedrive
synced 2024-06-15 04:05:13 +02:00
Retry session upload fragment when transient errors occur to prevent silent upload failure (#721)
* When uploading data to OneDrive via a session, and OneDrive throws an exception response, retry the fragment upload instead of silently failing without any error message * Add error message & error logging when uploading data via a session and OneDrive throws an exception
This commit is contained in:
parent
10adb43a09
commit
c876b9c575
11
src/log.d
11
src/log.d
|
@ -100,6 +100,17 @@ void vdebug(T...)(T args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vdebugUpload(T...)(T args)
|
||||||
|
{
|
||||||
|
if (verbose >= 2) {
|
||||||
|
writeln("\n[DEBUG] ", args);
|
||||||
|
if(writeLogFile){
|
||||||
|
// Write to log file
|
||||||
|
logfileWriteLine("\n[DEBUG] ", args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void error(T...)(T args)
|
void error(T...)(T args)
|
||||||
{
|
{
|
||||||
stderr.writeln(args);
|
stderr.writeln(args);
|
||||||
|
|
|
@ -2724,7 +2724,6 @@ final class SyncEngine
|
||||||
} else {
|
} else {
|
||||||
// response is not valid JSON, an error was returned from OneDrive
|
// response is not valid JSON, an error was returned from OneDrive
|
||||||
log.fileOnly("Uploading new file ", path, " ... error");
|
log.fileOnly("Uploading new file ", path, " ... error");
|
||||||
writeln("error");
|
|
||||||
uploadFailed = true;
|
uploadFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
48
src/upload.d
48
src/upload.d
|
@ -1,5 +1,5 @@
|
||||||
import std.algorithm, std.conv, std.datetime, std.file, std.json;
|
import std.algorithm, std.conv, std.datetime, std.file, std.json;
|
||||||
import std.stdio, core.thread;
|
import std.stdio, core.thread, std.string;
|
||||||
import progress, onedrive, util;
|
import progress, onedrive, util;
|
||||||
static import log;
|
static import log;
|
||||||
|
|
||||||
|
@ -172,8 +172,11 @@ struct UploadSession
|
||||||
size_t iteration = (roundTo!int(double(fileSize)/double(fragmentSize)))+1;
|
size_t iteration = (roundTo!int(double(fileSize)/double(fragmentSize)))+1;
|
||||||
Progress p = new Progress(iteration);
|
Progress p = new Progress(iteration);
|
||||||
p.title = "Uploading";
|
p.title = "Uploading";
|
||||||
|
long fragmentCount = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
fragmentCount++;
|
||||||
|
log.vdebugUpload("Fragment: ", fragmentCount, " of ", iteration);
|
||||||
p.next();
|
p.next();
|
||||||
long fragSize = fragmentSize < fileSize - offset ? fragmentSize : fileSize - offset;
|
long fragSize = fragmentSize < fileSize - offset ? fragmentSize : fileSize - offset;
|
||||||
// If the resume upload fails, we need to check for a return code here
|
// If the resume upload fails, we need to check for a return code here
|
||||||
|
@ -186,13 +189,31 @@ struct UploadSession
|
||||||
fileSize
|
fileSize
|
||||||
);
|
);
|
||||||
} catch (OneDriveException e) {
|
} catch (OneDriveException e) {
|
||||||
// there was an error remove session file
|
// there was an error response from OneDrive when uploading the file fragment
|
||||||
if (exists(sessionFilePath)) {
|
// insert a new line as well, so that the below error is inserted on the console in the right location
|
||||||
remove(sessionFilePath);
|
log.vlog("\nFragment upload failed - received an exception response from OneDrive");
|
||||||
|
// display what the error is
|
||||||
|
displayOneDriveErrorMessage(e.msg);
|
||||||
|
// retry fragment upload in case error is transient
|
||||||
|
log.vlog("Retrying fragment upload");
|
||||||
|
try {
|
||||||
|
response = onedrive.uploadFragment(
|
||||||
|
session["uploadUrl"].str,
|
||||||
|
session["localPath"].str,
|
||||||
|
offset,
|
||||||
|
fragSize,
|
||||||
|
fileSize
|
||||||
|
);
|
||||||
|
} catch (OneDriveException e) {
|
||||||
|
// OneDrive threw another error on retry
|
||||||
|
log.vlog("Retry to upload fragment failed");
|
||||||
|
// display what the error is
|
||||||
|
displayOneDriveErrorMessage(e.msg);
|
||||||
|
// set response to null as the fragment upload was in error twice
|
||||||
|
response = null;
|
||||||
}
|
}
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
// fragment uploaded without issue
|
// was the fragment uploaded without issue?
|
||||||
if (response.type() == JSONType.object){
|
if (response.type() == JSONType.object){
|
||||||
offset += fragmentSize;
|
offset += fragmentSize;
|
||||||
if (offset >= fileSize) break;
|
if (offset >= fileSize) break;
|
||||||
|
@ -201,11 +222,13 @@ struct UploadSession
|
||||||
session["nextExpectedRanges"] = response["nextExpectedRanges"];
|
session["nextExpectedRanges"] = response["nextExpectedRanges"];
|
||||||
save();
|
save();
|
||||||
} else {
|
} else {
|
||||||
// not a JSON object
|
// not a JSON object - fragment upload failed
|
||||||
log.vlog("File upload session failed - invalid response from OneDrive");
|
log.vlog("File upload session failed - invalid response from OneDrive");
|
||||||
if (exists(sessionFilePath)) {
|
if (exists(sessionFilePath)) {
|
||||||
remove(sessionFilePath);
|
remove(sessionFilePath);
|
||||||
}
|
}
|
||||||
|
// set response to null as error
|
||||||
|
response = null;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,9 +243,20 @@ struct UploadSession
|
||||||
// session elements were not present
|
// session elements were not present
|
||||||
log.vlog("Session has no valid upload URL ... skipping this file upload");
|
log.vlog("Session has no valid upload URL ... skipping this file upload");
|
||||||
// return an empty JSON response
|
// return an empty JSON response
|
||||||
|
response = null;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse and display error message received from OneDrive
|
||||||
|
private void displayOneDriveErrorMessage(string message) {
|
||||||
|
log.error("ERROR: OneDrive returned an error with the following message:");
|
||||||
|
auto errorArray = splitLines(message);
|
||||||
|
log.error(" Error Message: ", errorArray[0]);
|
||||||
|
// extract 'message' as the reason
|
||||||
|
JSONValue errorMessage = parseJSON(replace(message, errorArray[0], ""));
|
||||||
|
log.error(" Error Reason: ", errorMessage["error"]["message"].str);
|
||||||
|
}
|
||||||
|
|
||||||
private void save()
|
private void save()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue