Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5123)

Unified Diff: chrome/browser/chromeos/policy/upload_job_impl.cc

Issue 1875443003: Retry uploading in UploadJobImpl when error occurs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Retry when token request failed, add backoff, add log messages Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/policy/upload_job_impl.cc
diff --git a/chrome/browser/chromeos/policy/upload_job_impl.cc b/chrome/browser/chromeos/policy/upload_job_impl.cc
index d557c287b505fc11be6cbe0f215af769a4bd996e..98b0c875d1b6bfeef7237b5ad9bcdf29d93fc6c4 100644
--- a/chrome/browser/chromeos/policy/upload_job_impl.cc
+++ b/chrome/browser/chromeos/policy/upload_job_impl.cc
@@ -8,6 +8,7 @@
#include <set>
#include <utility>
+#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
@@ -28,12 +29,18 @@ const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
// Value the "Content-Type" field will be set to in the POST request.
const char kUploadContentType[] = "multipart/form-data";
-// Number of upload retries.
-const int kMaxRetries = 1;
+// Number of upload attempts.
+const int kMaxAttempts = 4;
// Max size of MIME boundary according to RFC 1341, section 7.2.1.
const size_t kMaxMimeBoundarySize = 70;
+// Delay after first unsuccessful upload attempt. After each additional failure,
+// the delay increases with this value.
Andrew T Wilson (Slow) 2016/05/02 09:15:49 Consider just having a simple fixed 25s delay - th
Marton Hunyady 2016/05/04 11:26:41 Done.
+// Value chosen because the server is waiting 2 minutes for a screenshot.
+// 1st attempt is 0s after request, 2nd: 18s, 3rd: 54s, 4th: 108s.
+const long kRetryDelayMs = 18000;
+
} // namespace
UploadJobImpl::Delegate::~Delegate() {
@@ -127,7 +134,8 @@ UploadJobImpl::UploadJobImpl(
OAuth2TokenService* token_service,
scoped_refptr<net::URLRequestContextGetter> url_context_getter,
Delegate* delegate,
- std::unique_ptr<MimeBoundaryGenerator> boundary_generator)
+ std::unique_ptr<MimeBoundaryGenerator> boundary_generator,
+ const scoped_refptr<base::SequencedTaskRunner> task_runner)
Andrew T Wilson (Slow) 2016/05/02 09:15:49 pass as a reference
Marton Hunyady 2016/05/04 11:26:41 Removed const, passing as value.
: OAuth2TokenService::Consumer("cros_upload_job"),
upload_url_(upload_url),
account_id_(account_id),
@@ -136,7 +144,9 @@ UploadJobImpl::UploadJobImpl(
delegate_(delegate),
boundary_generator_(std::move(boundary_generator)),
state_(IDLE),
- retry_(0) {
+ retry_(0),
+ task_runner_(task_runner),
Andrew T Wilson (Slow) 2016/05/02 09:15:49 Now that we have a task_runner, we need to make su
Marton Hunyady 2016/05/04 11:26:41 Done.
+ weak_factory_(this) {
DCHECK(token_service_);
DCHECK(url_context_getter_);
DCHECK(delegate_);
@@ -169,6 +179,7 @@ void UploadJobImpl::Start() {
DCHECK_EQ(IDLE, state_);
if (state_ != IDLE)
return;
+ retry_ = 0;
Andrew T Wilson (Slow) 2016/05/02 09:15:49 Why is this necessary? You can only get to IDLE st
Marton Hunyady 2016/05/04 11:26:41 Done.
RequestAccessToken();
}
@@ -264,13 +275,13 @@ void UploadJobImpl::CreateAndStartURLFetcher(const std::string& access_token) {
upload_fetcher_->Start();
}
-void UploadJobImpl::StartUpload(const std::string& access_token) {
+void UploadJobImpl::StartUpload() {
if (!SetUpMultipart()) {
LOG(ERROR) << "Multipart message assembly failed.";
state_ = ERROR;
return;
}
- CreateAndStartURLFetcher(access_token);
+ CreateAndStartURLFetcher(access_token_);
state_ = UPLOADING;
}
@@ -284,7 +295,7 @@ void UploadJobImpl::OnGetTokenSuccess(
// Also cache the token locally, so that we can revoke it later if necessary.
access_token_ = access_token;
- StartUpload(access_token);
+ StartUpload();
}
void UploadJobImpl::OnGetTokenFailure(
@@ -292,59 +303,69 @@ void UploadJobImpl::OnGetTokenFailure(
const GoogleServiceAuthError& error) {
DCHECK_EQ(ACQUIRING_TOKEN, state_);
DCHECK_EQ(access_token_request_.get(), request);
- access_token_request_.reset();
Andrew T Wilson (Slow) 2016/05/02 09:15:49 Why did you remove this? I think you still want to
Marton Hunyady 2016/05/04 11:26:41 Done.
LOG(ERROR) << "Token request failed: " << error.ToString();
- state_ = ERROR;
- delegate_->OnFailure(AUTHENTICATION_ERROR);
+ HandleError(AUTHENTICATION_ERROR);
+}
+
+void UploadJobImpl::HandleError(ErrorCode errorCode) {
+ retry_++;
Andrew T Wilson (Slow) 2016/05/02 09:15:49 Should log the errorCode here.
Marton Hunyady 2016/05/04 11:26:41 Done.
+ upload_fetcher_.reset();
+ if (retry_ >= kMaxAttempts) {
+ // Maximum number of attempts reached, failure.
+ LOG(ERROR) << "Upload failed, maximum number of attempts reached.";
+ access_token_.clear();
+ post_data_.reset();
+ state_ = ERROR;
+ delegate_->OnFailure(errorCode);
+ } else {
+ if (errorCode == AUTHENTICATION_ERROR) {
+ LOG(ERROR) << "Upload failed, retrying upload with a new token.";
+ // Request new token and retry.
+ OAuth2TokenService::ScopeSet scope_set;
+ scope_set.insert(GaiaConstants::kDeviceManagementServiceOAuth);
+ token_service_->InvalidateAccessToken(account_id_, scope_set,
+ access_token_);
+ access_token_.clear();
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&UploadJobImpl::RequestAccessToken,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kRetryDelayMs * retry_));
+ } else {
+ // Retry without a new token.
+ state_ = ACQUIRING_TOKEN;
+ LOG(WARNING) << "Upload failed, retrying upload with the same token.";
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&UploadJobImpl::StartUpload, weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kRetryDelayMs * retry_));
+ }
+ }
}
void UploadJobImpl::OnURLFetchComplete(const net::URLFetcher* source) {
DCHECK_EQ(upload_fetcher_.get(), source);
+ DCHECK_EQ(UPLOADING, state_);
const net::URLRequestStatus& status = source->GetStatus();
if (!status.is_success()) {
LOG(ERROR) << "URLRequestStatus error " << status.error();
- upload_fetcher_.reset();
- state_ = ERROR;
- post_data_.reset();
- delegate_->OnFailure(NETWORK_ERROR);
- return;
- }
-
- const int response_code = source->GetResponseCode();
- const bool success = response_code == net::HTTP_OK;
- if (!success)
- LOG(ERROR) << "POST request failed with HTTP status code " << response_code;
-
- if (response_code == net::HTTP_UNAUTHORIZED) {
- if (retry_ >= kMaxRetries) {
+ HandleError(NETWORK_ERROR);
+ } else {
+ const int response_code = source->GetResponseCode();
+ if (response_code == net::HTTP_OK) {
+ // Successful uploading
Andrew T Wilson (Slow) 2016/05/02 09:15:49 nit: uploading -> upload.
Marton Hunyady 2016/05/04 11:26:41 Done.
upload_fetcher_.reset();
- LOG(ERROR) << "Unauthorized request.";
- state_ = ERROR;
+ access_token_.clear();
post_data_.reset();
- delegate_->OnFailure(AUTHENTICATION_ERROR);
- return;
+ state_ = SUCCESS;
+ delegate_->OnSuccess();
+ } else if (response_code == net::HTTP_UNAUTHORIZED) {
+ LOG(ERROR) << "Unauthorized request.";
+ HandleError(AUTHENTICATION_ERROR);
+ } else {
+ LOG(ERROR) << "POST request failed with HTTP status code "
+ << response_code << ".";
+ HandleError(SERVER_ERROR);
}
- retry_++;
- upload_fetcher_.reset();
- OAuth2TokenService::ScopeSet scope_set;
- scope_set.insert(GaiaConstants::kDeviceManagementServiceOAuth);
- token_service_->InvalidateAccessToken(account_id_, scope_set,
- access_token_);
- access_token_.clear();
- RequestAccessToken();
- return;
- }
-
- upload_fetcher_.reset();
- access_token_.clear();
- upload_fetcher_.reset();
- post_data_.reset();
- if (success) {
- state_ = SUCCESS;
- delegate_->OnSuccess();
- } else {
- state_ = ERROR;
- delegate_->OnFailure(SERVER_ERROR);
}
}

Powered by Google App Engine
This is Rietveld 408576698