summaryrefslogtreecommitdiffstats
path: root/chrome/browser/metrics/metrics_reporting_scheduler.cc
blob: 05ff108381b459114fde6848899aa5a04c5e1f64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/metrics/metrics_reporting_scheduler.h"

#include "base/compiler_specific.h"
#include "chrome/browser/metrics/metrics_service.h"

using base::Time;
using base::TimeDelta;

// The delay, in seconds, after startup before sending the first log message.
static const int kInitialUploadIntervalSeconds = 60;

// The delay, in seconds, between uploading when there are queued logs from
// previous sessions to send.
static const int kUnsentLogsIntervalSeconds = 15;

// Standard interval between log uploads, in seconds.
static const int kStandardUploadIntervalSeconds = 30 * 60;  // Thirty minutes.

// When uploading metrics to the server fails, we progressively wait longer and
// longer before sending the next log. This backoff process helps reduce load
// on a server that is having issues.
// The following is the multiplier we use to expand that inter-log duration.
static const double kBackoffMultiplier = 1.1;

// The maximum backoff multiplier.
static const int kMaxBackoffMultiplier = 10;


MetricsReportingScheduler::MetricsReportingScheduler(
    const base::Closure& upload_callback)
    : upload_callback_(upload_callback),
      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
      upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds)),
      running_(false),
      timer_pending_(false),
      callback_pending_(false) {
}

MetricsReportingScheduler::~MetricsReportingScheduler() {}

void MetricsReportingScheduler::Start() {
  running_ = true;
  ScheduleNextCallback();
}

void MetricsReportingScheduler::Stop() {
  running_ = false;
}

void MetricsReportingScheduler::UploadFinished(bool server_is_healthy,
                                               bool more_logs_remaining) {
  DCHECK(callback_pending_);
  callback_pending_ = false;
  // If the server is having issues, back off. Otherwise, reset to default
  // (unless there are more logs to send, in which case the next upload should
  // happen sooner).
  if (!server_is_healthy) {
    BackOffUploadInterval();
  } else if (more_logs_remaining) {
    upload_interval_ = TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
  } else {
    upload_interval_ = TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
  }

  if (running_)
    ScheduleNextCallback();
}

void MetricsReportingScheduler::UploadCancelled() {
  DCHECK(callback_pending_);
  callback_pending_ = false;
  if (running_)
    ScheduleNextCallback();
}

void MetricsReportingScheduler::TriggerUpload() {
  timer_pending_ = false;
  callback_pending_ = true;
  upload_callback_.Run();
}

void MetricsReportingScheduler::ScheduleNextCallback() {
  DCHECK(running_);
  if (timer_pending_ || callback_pending_)
    return;

  timer_pending_ = true;

  MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&MetricsReportingScheduler::TriggerUpload,
                 weak_ptr_factory_.GetWeakPtr()),
      upload_interval_);
}

void MetricsReportingScheduler::BackOffUploadInterval() {
  DCHECK(kBackoffMultiplier > 1.0);
  upload_interval_ = TimeDelta::FromMicroseconds(
      static_cast<int64>(kBackoffMultiplier *
                         upload_interval_.InMicroseconds()));

  TimeDelta max_interval = kMaxBackoffMultiplier *
      TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
  if (upload_interval_ > max_interval || upload_interval_.InSeconds() < 0) {
    upload_interval_ = max_interval;
  }
}