Commit d498e91b authored by Dan Harrington's avatar Dan Harrington Committed by Commit Bot

Add start of scheduling logic for v2

Instead of using FeedSchedulerHost directly, this CL starts importing
its capabilities into FeedStream.
- Added RefreshTaskScheduler interface for scheduling the background task.
- Added AllRefreshThrottler to wrap use of RefreshThrottler
- FeedStream handles various events, and reacts by attempting to do a
  refresh. Actual refresh code is TBD.
  Injection of these events will happen externally.
- scheduling.cc implements some scheduling logic/constants.
- Added a FeedStream::EventObserver interface to simplify
  testing and push metric logging code out of FeedStream.

Unit tests in this CL are admittedly minimal, and should be
improved. I'm thinking it makes sense to wait until we have code that
actually does a refresh.

Things FeedSchedulerHost does not included here:
- Reconciling host state vs feed library state (we don't need this)
- Lots of UMA (we'll replicate some of this)
- Resetting the scheduled fetch on fetch success (todo)

Bug: 1044139
Change-Id: I8fbecfad67ff1639b419fe65962f4887ec2ea305
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2031721
Commit-Queue: Dan H <harringtond@chromium.org>
Reviewed-by: default avatarCarlos Knippschild <carlosk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748903}
parent d83d5887
...@@ -10,17 +10,27 @@ if (is_android) { ...@@ -10,17 +10,27 @@ if (is_android) {
source_set("feed_core_v2") { source_set("feed_core_v2") {
sources = [ sources = [
"enums.h",
"feed_network.cc", "feed_network.cc",
"feed_network.h", "feed_network.h",
"feed_network_impl.cc", "feed_network_impl.cc",
"feed_network_impl.h", "feed_network_impl.h",
"feed_stream.cc", "feed_stream.cc",
"feed_stream.h", "feed_stream.h",
"feed_stream_api.h",
"feed_stream_background.cc", "feed_stream_background.cc",
"feed_stream_background.h", "feed_stream_background.h",
"master_refresh_throttler.cc",
"master_refresh_throttler.h",
"proto_util.cc", "proto_util.cc",
"proto_util.h", "proto_util.h",
"public/feed_service.cc",
"public/feed_service.h",
"public/feed_stream_api.h",
"refresh_task_scheduler.h",
"scheduling.cc",
"scheduling.h",
"stream_event_metrics.cc",
"stream_event_metrics.h",
"stream_model.cc", "stream_model.cc",
"stream_model.h", "stream_model.h",
"stream_model/ephemeral_change.cc", "stream_model/ephemeral_change.cc",
......
// Copyright 2020 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.
#ifndef COMPONENTS_FEED_CORE_V2_ENUMS_H_
#define COMPONENTS_FEED_CORE_V2_ENUMS_H_
#include "components/feed/core/common/enums.h"
namespace feed {
// Describes the behavior for attempting to refresh (over the network) while
// loading the feed.
enum class LoadRefreshBehavior {
// Wait for feed refresh before showing the result.
kWaitForRefresh,
// Load what is available locally, begin the refresh, and populate results
// below the fold when they are received.
kRefreshInline,
// Wait a limited amount of time for the network fetch. If the fetch doesn't
// complete in time, just show the user what's available locally.
kLimitedWaitForRefresh,
};
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_ENUMS_H_
...@@ -5,32 +5,54 @@ ...@@ -5,32 +5,54 @@
#include "components/feed/core/v2/feed_stream.h" #include "components/feed/core/v2/feed_stream.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/clock.h"
#include "base/time/tick_clock.h"
#include "components/feed/core/common/pref_names.h"
#include "components/feed/core/shared_prefs/pref_names.h" #include "components/feed/core/shared_prefs/pref_names.h"
#include "components/feed/core/v2/feed_network.h" #include "components/feed/core/v2/feed_network.h"
#include "components/feed/core/v2/feed_stream_background.h" #include "components/feed/core/v2/feed_stream_background.h"
#include "components/feed/core/v2/refresh_task_scheduler.h"
#include "components/feed/core/v2/scheduling.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
namespace feed { namespace feed {
FeedStream::FeedStream( FeedStream::FeedStream(
RefreshTaskScheduler* refresh_task_scheduler,
EventObserver* stream_event_observer,
Delegate* delegate,
PrefService* profile_prefs, PrefService* profile_prefs,
FeedNetwork* feed_network, FeedNetwork* feed_network,
base::Clock* clock, base::Clock* clock,
base::TickClock* tick_clock, base::TickClock* tick_clock,
scoped_refptr<base::SequencedTaskRunner> background_task_runner) scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: profile_prefs_(profile_prefs), : refresh_task_scheduler_(refresh_task_scheduler),
stream_event_observer_(stream_event_observer),
delegate_(delegate),
profile_prefs_(profile_prefs),
feed_network_(feed_network), feed_network_(feed_network),
clock_(clock), clock_(clock),
tick_clock_(tick_clock), tick_clock_(tick_clock),
background_task_runner_(background_task_runner), background_task_runner_(background_task_runner),
background_(std::make_unique<FeedStreamBackground>()), background_(std::make_unique<FeedStreamBackground>()),
task_queue_(this) { task_queue_(this),
user_classifier_(profile_prefs, clock),
refresh_throttler_(profile_prefs, clock) {
// TODO(harringtond): Use these members. // TODO(harringtond): Use these members.
(void)clock_;
(void)tick_clock_;
(void)feed_network_; (void)feed_network_;
} }
void FeedStream::InitializeScheduling() {
if (!IsArticlesListVisible()) {
refresh_task_scheduler_->Cancel();
return;
}
refresh_task_scheduler_->EnsureScheduled(
GetUserClassTriggerThreshold(GetUserClass(), TriggerType::kFixedTimer));
}
FeedStream::~FeedStream() { FeedStream::~FeedStream() {
// Delete |background_| in the background sequence. // Delete |background_| in the background sequence.
background_task_runner_->PostTask( background_task_runner_->PostTask(
...@@ -47,6 +69,117 @@ bool FeedStream::IsArticlesListVisible() { ...@@ -47,6 +69,117 @@ bool FeedStream::IsArticlesListVisible() {
return profile_prefs_->GetBoolean(prefs::kArticlesListVisible); return profile_prefs_->GetBoolean(prefs::kArticlesListVisible);
} }
UserClass FeedStream::GetUserClass() {
return user_classifier_.GetUserClass();
}
base::Time FeedStream::GetLastFetchTime() {
const base::Time fetch_time =
profile_prefs_->GetTime(feed::prefs::kLastFetchAttemptTime);
// Ignore impossible time values.
if (fetch_time > clock_->Now())
return base::Time();
return fetch_time;
}
void FeedStream::OnTaskQueueIsIdle() {} void FeedStream::OnTaskQueueIsIdle() {}
// TODO(harringtond): Ensure this function gets test coverage when fetching
// functionality is added.
ShouldRefreshResult FeedStream::ShouldRefresh(TriggerType trigger) {
if (delegate_->IsOffline()) {
return ShouldRefreshResult::kDontRefreshNetworkOffline;
}
if (!delegate_->IsEulaAccepted()) {
return ShouldRefreshResult::kDontRefreshEulaNotAccepted;
}
if (!IsArticlesListVisible()) {
return ShouldRefreshResult::kDontRefreshArticlesHidden;
}
// TODO(harringtond): |suppress_refreshes_until_| was historically used for
// privacy purposes after clearing data to make sure sync data made it to the
// server. I'm not sure we need this now. But also, it was documented as not
// affecting manually triggered refreshes, but coded in a way that it does.
// I've tried to keep the same functionality as the old feed code, but we
// should revisit this.
if (tick_clock_->NowTicks() < suppress_refreshes_until_) {
return ShouldRefreshResult::kDontRefreshRefreshSuppressed;
}
const UserClass user_class = GetUserClass();
if (clock_->Now() - GetLastFetchTime() <
GetUserClassTriggerThreshold(user_class, trigger)) {
return ShouldRefreshResult::kDontRefreshNotStale;
}
if (!refresh_throttler_.RequestQuota(user_class)) {
return ShouldRefreshResult::kDontRefreshRefreshThrottled;
}
UMA_HISTOGRAM_ENUMERATION("ContentSuggestions.Feed.Scheduler.RefreshTrigger",
trigger);
return ShouldRefreshResult::kShouldRefresh;
}
void FeedStream::OnEulaAccepted() {
MaybeTriggerRefresh(TriggerType::kForegrounded);
}
void FeedStream::OnHistoryDeleted() {
// Due to privacy, we should not fetch for a while (unless the user
// explicitly asks for new suggestions) to give sync the time to propagate
// the changes in history to the server.
suppress_refreshes_until_ =
tick_clock_->NowTicks() + kSuppressRefreshDuration;
ClearAll();
}
void FeedStream::OnCacheDataCleared() {
ClearAll();
}
void FeedStream::OnSignedIn() {
ClearAll();
}
void FeedStream::OnSignedOut() {
ClearAll();
}
void FeedStream::OnEnterForeground() {
MaybeTriggerRefresh(TriggerType::kForegrounded);
}
void FeedStream::ExecuteRefreshTask() {
if (!IsArticlesListVisible()) {
// While the check and cancel isn't strictly necessary, a long lived session
// could be issuing refreshes due to the background trigger while articles
// are not visible.
refresh_task_scheduler_->Cancel();
return;
}
MaybeTriggerRefresh(TriggerType::kFixedTimer);
}
void FeedStream::ClearAll() {
// TODO(harringtond): How should we handle in-progress tasks.
stream_event_observer_->OnClearAll(clock_->Now() - GetLastFetchTime());
// TODO(harringtond): This should result in clearing feed data
// and _maybe_ triggering refresh with TriggerType::kNtpShown.
// That work should be embedded in a task.
}
void FeedStream::MaybeTriggerRefresh(TriggerType trigger,
bool clear_all_before_refresh) {
stream_event_observer_->OnMaybeTriggerRefresh(trigger,
clear_all_before_refresh);
// TODO(harringtond): Implement refresh (with LoadStreamTask).
}
} // namespace feed } // namespace feed
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/task_runner_util.h" #include "base/task_runner_util.h"
#include "components/feed/core/v2/feed_stream_api.h" #include "components/feed/core/common/enums.h"
#include "components/feed/core/common/user_classifier.h"
#include "components/feed/core/v2/master_refresh_throttler.h"
#include "components/feed/core/v2/public/feed_stream_api.h"
#include "components/offline_pages/task/task_queue.h" #include "components/offline_pages/task/task_queue.h"
class PrefService; class PrefService;
...@@ -22,6 +25,7 @@ class TickClock; ...@@ -22,6 +25,7 @@ class TickClock;
namespace feed { namespace feed {
class FeedNetwork; class FeedNetwork;
class RefreshTaskScheduler;
class FeedStreamBackground; class FeedStreamBackground;
// Implements FeedStreamApi. |FeedStream| additionally exposes functionality // Implements FeedStreamApi. |FeedStream| additionally exposes functionality
...@@ -29,7 +33,27 @@ class FeedStreamBackground; ...@@ -29,7 +33,27 @@ class FeedStreamBackground;
class FeedStream : public FeedStreamApi, class FeedStream : public FeedStreamApi,
public offline_pages::TaskQueue::Delegate { public offline_pages::TaskQueue::Delegate {
public: public:
FeedStream(PrefService* profile_prefs, class Delegate {
public:
// Returns true if Chrome's EULA has been accepted.
virtual bool IsEulaAccepted() = 0;
// Returns true if the device is offline.
virtual bool IsOffline() = 0;
};
// An observer of stream events for testing and for tracking metrics.
// Concrete implementation should have no observable effects on the Feed.
class EventObserver {
public:
virtual void OnMaybeTriggerRefresh(TriggerType trigger,
bool clear_all_before_refresh) = 0;
virtual void OnClearAll(base::TimeDelta time_since_last_clear) = 0;
};
FeedStream(RefreshTaskScheduler* refresh_task_scheduler,
EventObserver* stream_event_observer,
Delegate* delegate,
PrefService* profile_prefs,
FeedNetwork* feed_network, FeedNetwork* feed_network,
base::Clock* clock, base::Clock* clock,
base::TickClock* tick_clock, base::TickClock* tick_clock,
...@@ -39,6 +63,9 @@ class FeedStream : public FeedStreamApi, ...@@ -39,6 +63,9 @@ class FeedStream : public FeedStreamApi,
FeedStream(const FeedStream&) = delete; FeedStream(const FeedStream&) = delete;
FeedStream& operator=(const FeedStream&) = delete; FeedStream& operator=(const FeedStream&) = delete;
// Initializes scheduling. This should be called at startup.
void InitializeScheduling();
// FeedStreamApi. // FeedStreamApi.
void SetArticlesListVisible(bool is_visible) override; void SetArticlesListVisible(bool is_visible) override;
bool IsArticlesListVisible() override; bool IsArticlesListVisible() override;
...@@ -46,6 +73,34 @@ class FeedStream : public FeedStreamApi, ...@@ -46,6 +73,34 @@ class FeedStream : public FeedStreamApi,
// offline_pages::TaskQueue::Delegate. // offline_pages::TaskQueue::Delegate.
void OnTaskQueueIsIdle() override; void OnTaskQueueIsIdle() override;
// Event indicators. These functions are called from an external source
// to indicate an event.
// Called when Chrome's EULA has been accepted. This should happen when
// Delegate::IsEulaAccepted() changes from false to true.
void OnEulaAccepted();
// Invoked when Chrome is foregrounded.
void OnEnterForeground();
// The user signed in to Chrome.
void OnSignedIn();
// The user signed out of Chrome.
void OnSignedOut();
// The user has deleted their Chrome history.
void OnHistoryDeleted();
// Chrome's cached data was cleared.
void OnCacheDataCleared();
// Invoked by RefreshTaskScheduler's scheduled task.
void ExecuteRefreshTask();
// State shared for the sake of implementing FeedStream. Typically these
// functions are used by tasks.
// Returns the computed UserClass for the active user.
UserClass GetUserClass();
// Returns the time of the last content fetch.
base::Time GetLastFetchTime();
// Provides access to |FeedStreamBackground|. // Provides access to |FeedStreamBackground|.
// PostTask's to |background_callback| in the background thread. When // PostTask's to |background_callback| in the background thread. When
// complete, executes |foreground_result_callback| with the result. // complete, executes |foreground_result_callback| with the result.
...@@ -61,6 +116,19 @@ class FeedStream : public FeedStreamApi, ...@@ -61,6 +116,19 @@ class FeedStream : public FeedStreamApi,
} }
private: private:
void MaybeTriggerRefresh(TriggerType trigger,
bool clear_all_before_refresh = false);
// Determines whether or not a fetch should be allowed.
// If a fetch is allowed, quota is reserved with the assumption that a fetch
// will follow shortly.
ShouldRefreshResult ShouldRefresh(TriggerType trigger);
void ClearAll();
RefreshTaskScheduler* refresh_task_scheduler_;
EventObserver* stream_event_observer_;
Delegate* delegate_;
PrefService* profile_prefs_; PrefService* profile_prefs_;
FeedNetwork* feed_network_; FeedNetwork* feed_network_;
base::Clock* clock_; base::Clock* clock_;
...@@ -71,6 +139,11 @@ class FeedStream : public FeedStreamApi, ...@@ -71,6 +139,11 @@ class FeedStream : public FeedStreamApi,
std::unique_ptr<FeedStreamBackground> background_; std::unique_ptr<FeedStreamBackground> background_;
offline_pages::TaskQueue task_queue_; offline_pages::TaskQueue task_queue_;
// Mutable state.
UserClassifier user_classifier_;
MasterRefreshThrottler refresh_throttler_;
base::TimeTicks suppress_refreshes_until_;
}; };
} // namespace feed } // namespace feed
......
...@@ -3,13 +3,16 @@ ...@@ -3,13 +3,16 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "components/feed/core/v2/feed_stream.h" #include "components/feed/core/v2/feed_stream.h"
#include "base/optional.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/simple_test_clock.h" #include "base/test/simple_test_clock.h"
#include "base/test/simple_test_tick_clock.h" #include "base/test/simple_test_tick_clock.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "components/feed/core/common/pref_names.h"
#include "components/feed/core/shared_prefs/pref_names.h" #include "components/feed/core/shared_prefs/pref_names.h"
#include "components/feed/core/v2/feed_network.h" #include "components/feed/core/v2/feed_network.h"
#include "components/feed/core/v2/feed_stream_background.h" #include "components/feed/core/v2/feed_stream_background.h"
#include "components/feed/core/v2/refresh_task_scheduler.h"
#include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h" #include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -19,6 +22,7 @@ namespace { ...@@ -19,6 +22,7 @@ namespace {
class TestFeedNetwork : public FeedNetwork { class TestFeedNetwork : public FeedNetwork {
public: public:
// FeedNetwork implementation.
void SendQueryRequest( void SendQueryRequest(
const feedwire::Request& request, const feedwire::Request& request,
base::OnceCallback<void(QueryRequestResult)> callback) override {} base::OnceCallback<void(QueryRequestResult)> callback) override {}
...@@ -28,22 +32,58 @@ class TestFeedNetwork : public FeedNetwork { ...@@ -28,22 +32,58 @@ class TestFeedNetwork : public FeedNetwork {
void CancelRequests() override {} void CancelRequests() override {}
}; };
class FeedStreamTest : public testing::Test { class FakeRefreshTaskScheduler : public RefreshTaskScheduler {
public:
// RefreshTaskScheduler implementation.
void EnsureScheduled(base::TimeDelta period) override {
scheduled_period = period;
}
void Cancel() override { canceled = true; }
void RefreshTaskComplete() override { refresh_task_complete = true; }
base::Optional<base::TimeDelta> scheduled_period;
bool canceled = false;
bool refresh_task_complete = false;
};
class TestEventObserver : public FeedStream::EventObserver {
public:
// FeedStreamUnittest::StreamEventObserver.
void OnMaybeTriggerRefresh(TriggerType trigger,
bool clear_all_before_refresh) override {
refresh_trigger_type = trigger;
}
void OnClearAll(base::TimeDelta time_since_last_clear) override {
this->time_since_last_clear = time_since_last_clear;
}
// Test access.
base::Optional<base::TimeDelta> time_since_last_clear;
base::Optional<TriggerType> refresh_trigger_type;
};
class FeedStreamTest : public testing::Test, public FeedStream::Delegate {
public: public:
void SetUp() override { void SetUp() override {
feed::prefs::RegisterFeedSharedProfilePrefs(profile_prefs_.registry()); feed::prefs::RegisterFeedSharedProfilePrefs(profile_prefs_.registry());
feed::RegisterProfilePrefs(profile_prefs_.registry());
stream_ = std::make_unique<FeedStream>( stream_ = std::make_unique<FeedStream>(
&profile_prefs_, &network_, &clock_, &tick_clock_, &refresh_scheduler_, &event_observer_, this, &profile_prefs_, &network_,
task_environment_.GetMainThreadTaskRunner()); &clock_, &tick_clock_, task_environment_.GetMainThreadTaskRunner());
} }
// FeedStream::Delegate.
bool IsEulaAccepted() override { return true; }
bool IsOffline() override { return false; }
protected: protected:
TestEventObserver event_observer_;
TestingPrefServiceSimple profile_prefs_; TestingPrefServiceSimple profile_prefs_;
TestFeedNetwork network_; TestFeedNetwork network_;
base::SimpleTestClock clock_; base::SimpleTestClock clock_;
base::SimpleTestTickClock tick_clock_; base::SimpleTestTickClock tick_clock_;
FakeRefreshTaskScheduler refresh_scheduler_;
std::unique_ptr<FeedStream> stream_; std::unique_ptr<FeedStream> stream_;
base::test::SingleThreadTaskEnvironment task_environment_; base::test::SingleThreadTaskEnvironment task_environment_;
}; };
...@@ -86,5 +126,29 @@ TEST_F(FeedStreamTest, RunInBackgroundAndReturn) { ...@@ -86,5 +126,29 @@ TEST_F(FeedStreamTest, RunInBackgroundAndReturn) {
EXPECT_EQ(5, result_received); EXPECT_EQ(5, result_received);
} }
TEST_F(FeedStreamTest, RefreshIsScheduledOnInitialize) {
stream_->InitializeScheduling();
EXPECT_TRUE(refresh_scheduler_.scheduled_period);
}
TEST_F(FeedStreamTest, ScheduledRefreshTriggersRefresh) {
stream_->InitializeScheduling();
stream_->ExecuteRefreshTask();
EXPECT_EQ(TriggerType::kFixedTimer, event_observer_.refresh_trigger_type);
// TODO(harringtond): Once we actually perform the refresh, make sure
// RefreshTaskComplete() is called.
// EXPECT_TRUE(refresh_scheduler_.refresh_task_complete);
}
TEST_F(FeedStreamTest, DoNotRefreshIfArticlesListIsHidden) {
stream_->SetArticlesListVisible(false);
stream_->InitializeScheduling();
stream_->ExecuteRefreshTask();
EXPECT_TRUE(refresh_scheduler_.canceled);
EXPECT_FALSE(event_observer_.refresh_trigger_type);
}
} // namespace } // namespace
} // namespace feed } // namespace feed
// Copyright 2020 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 "components/feed/core/v2/master_refresh_throttler.h"
#include "components/prefs/pref_service.h"
namespace feed {
MasterRefreshThrottler::MasterRefreshThrottler(PrefService* profile_prefs,
base::Clock* clock)
: rare_throttler_(UserClass::kRareSuggestionsViewer, profile_prefs, clock),
active_viewer_throttler_(UserClass::kActiveSuggestionsViewer,
profile_prefs,
clock),
active_consumer_throttler_(UserClass::kActiveSuggestionsConsumer,
profile_prefs,
clock)
{}
bool MasterRefreshThrottler::RequestQuota(UserClass user_class) {
return GetThrottler(user_class).RequestQuota();
}
RefreshThrottler& MasterRefreshThrottler::GetThrottler(UserClass user_class) {
switch (user_class) {
case UserClass::kRareSuggestionsViewer:
return rare_throttler_;
case UserClass::kActiveSuggestionsViewer:
return active_viewer_throttler_;
case UserClass::kActiveSuggestionsConsumer:
return active_consumer_throttler_;
}
}
} // namespace feed
// Copyright 2020 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.
#ifndef COMPONENTS_FEED_CORE_V2_MASTER_REFRESH_THROTTLER_H_
#define COMPONENTS_FEED_CORE_V2_MASTER_REFRESH_THROTTLER_H_
#include "components/feed/core/common/enums.h"
#include "components/feed/core/common/refresh_throttler.h"
#include "components/feed/core/common/user_classifier.h"
class PrefService;
namespace feed {
// A refresh throttler that supports all |UserClass|es.
// TODO(harringtond): When v2 is the only Feed implementation, make
// |RefreshThrottler| a private implementation detail of this class.
class MasterRefreshThrottler {
public:
MasterRefreshThrottler(PrefService* profile_prefs, base::Clock* clock);
MasterRefreshThrottler(const MasterRefreshThrottler&) = delete;
MasterRefreshThrottler& operator=(const MasterRefreshThrottler&) = delete;
bool RequestQuota(UserClass user_class);
private:
RefreshThrottler& GetThrottler(UserClass user_class);
RefreshThrottler rare_throttler_;
RefreshThrottler active_viewer_throttler_;
RefreshThrottler active_consumer_throttler_;
};
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_MASTER_REFRESH_THROTTLER_H_
// Copyright 2020 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 "components/feed/core/v2/public/feed_service.h"
namespace feed {
FeedService::FeedService(std::unique_ptr<FeedStreamApi> stream)
: stream_(std::move(stream)) {}
FeedService::~FeedService() = default;
} // namespace feed
// Copyright 2020 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.
#ifndef COMPONENTS_FEED_CORE_V2_PUBLIC_FEED_SERVICE_H_
#define COMPONENTS_FEED_CORE_V2_PUBLIC_FEED_SERVICE_H_
#include <memory>
#include "components/feed/core/v2/public/feed_stream_api.h"
#include "components/keyed_service/core/keyed_service.h"
namespace feed {
class FeedService : public KeyedService {
public:
explicit FeedService(std::unique_ptr<FeedStreamApi> stream);
~FeedService() override;
FeedStreamApi* GetStream() { return stream_.get(); }
private:
std::unique_ptr<FeedStreamApi> stream_;
};
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_PUBLIC_FEED_SERVICE_H_
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef COMPONENTS_FEED_CORE_V2_FEED_STREAM_API_H_ #ifndef COMPONENTS_FEED_CORE_V2_PUBLIC_FEED_STREAM_API_H_
#define COMPONENTS_FEED_CORE_V2_FEED_STREAM_API_H_ #define COMPONENTS_FEED_CORE_V2_PUBLIC_FEED_STREAM_API_H_
namespace feed { namespace feed {
...@@ -20,4 +20,4 @@ class FeedStreamApi { ...@@ -20,4 +20,4 @@ class FeedStreamApi {
} // namespace feed } // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_FEED_STREAM_API_H_ #endif // COMPONENTS_FEED_CORE_V2_PUBLIC_FEED_STREAM_API_H_
// Copyright 2020 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.
#ifndef COMPONENTS_FEED_CORE_V2_REFRESH_TASK_SCHEDULER_H_
#define COMPONENTS_FEED_CORE_V2_REFRESH_TASK_SCHEDULER_H_
#include "base/time/time.h"
namespace feed {
// Schedules a repeating background task for refreshing the Feed.
// When the scheduled task executes, it calls FeedStream::ExecuteRefreshTask().
class RefreshTaskScheduler {
public:
RefreshTaskScheduler() = default;
// Schedules the task if it is not yet scheduled, or if the scheduling
// period changes.
virtual void EnsureScheduled(base::TimeDelta period) = 0;
// Cancel the task if it was previously scheduled.
virtual void Cancel() = 0;
// After FeedStream::ExecuteRefreshTask is called, the callee must call this
// function to indicate the work is complete.
virtual void RefreshTaskComplete() = 0;
};
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_REFRESH_TASK_SCHEDULER_H_
// Copyright 2020 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 "components/feed/core/v2/scheduling.h"
#include "base/time/time.h"
namespace feed {
base::TimeDelta GetUserClassTriggerThreshold(UserClass user_class,
TriggerType trigger) {
switch (user_class) {
case UserClass::kRareSuggestionsViewer:
switch (trigger) {
case TriggerType::kNtpShown:
return base::TimeDelta::FromHours(4);
case TriggerType::kForegrounded:
return base::TimeDelta::FromHours(24);
case TriggerType::kFixedTimer:
return base::TimeDelta::FromHours(96);
}
case UserClass::kActiveSuggestionsViewer:
switch (trigger) {
case TriggerType::kNtpShown:
return base::TimeDelta::FromHours(4);
case TriggerType::kForegrounded:
return base::TimeDelta::FromHours(24);
case TriggerType::kFixedTimer:
return base::TimeDelta::FromHours(48);
}
case UserClass::kActiveSuggestionsConsumer:
switch (trigger) {
case TriggerType::kNtpShown:
return base::TimeDelta::FromHours(1);
case TriggerType::kForegrounded:
return base::TimeDelta::FromHours(12);
case TriggerType::kFixedTimer:
return base::TimeDelta::FromHours(24);
}
}
}
LoadRefreshBehavior DetermineLoadRefreshBehavior(UserClass user_class,
bool has_content,
base::TimeDelta content_age) {
if (!has_content)
return LoadRefreshBehavior::kWaitForRefresh;
if (content_age >
GetUserClassTriggerThreshold(user_class, TriggerType::kForegrounded))
return LoadRefreshBehavior::kLimitedWaitForRefresh;
// TODO(harringtond): We are probably not going to support |kRefreshInline|.
return LoadRefreshBehavior::kRefreshInline;
}
} // namespace feed
// Copyright 2020 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.
#ifndef COMPONENTS_FEED_CORE_V2_SCHEDULING_H_
#define COMPONENTS_FEED_CORE_V2_SCHEDULING_H_
#include "base/time/time.h"
#include "components/feed/core/v2/enums.h"
namespace feed {
constexpr base::TimeDelta kSuppressRefreshDuration =
base::TimeDelta::FromMinutes(30);
// Returns a duration, T, depending on the UserClass and TriggerType.
// The following should be true:
// - At most one fetch is attempted per T.
// - Content is considered stale if time since last fetch is > T. We'll prefer
// to refresh stale content before showing it. See LoadRefreshBehavior.
// - For TriggerType::kFixedTimer, T is the time between scheduled fetches.
base::TimeDelta GetUserClassTriggerThreshold(UserClass user_class,
TriggerType trigger);
// Determines which LoadRefreshBehavior should be used when refreshing the
// stream.
LoadRefreshBehavior DetermineLoadRefreshBehavior(UserClass user_class,
bool has_content,
base::TimeDelta content_age);
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_SCHEDULING_H_
// Copyright 2020 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 "components/feed/core/v2/stream_event_metrics.h"
#include "base/metrics/histogram_macros.h"
namespace feed {
void StreamEventMetrics::OnMaybeTriggerRefresh(TriggerType trigger,
bool clear_all_before_refresh) {
// TODO(harringtond): Either add UMA for this or remove it.
}
void StreamEventMetrics::OnClearAll(base::TimeDelta time_since_last_clear) {
UMA_HISTOGRAM_CUSTOM_TIMES(
"ContentSuggestions.Feed.Scheduler.TimeSinceLastFetchOnClear",
time_since_last_clear, base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromDays(7),
/*bucket_count=*/50);
}
} // namespace feed
// Copyright 2020 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.
#ifndef COMPONENTS_FEED_CORE_V2_STREAM_EVENT_METRICS_H_
#define COMPONENTS_FEED_CORE_V2_STREAM_EVENT_METRICS_H_
#include "components/feed/core/v2/feed_stream.h"
namespace feed {
// Reports UMA metrics for stream events.
class StreamEventMetrics : public FeedStream::EventObserver {
public:
void OnMaybeTriggerRefresh(TriggerType trigger,
bool clear_all_before_refresh) override;
void OnClearAll(base::TimeDelta time_since_last_clear) override;
};
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_STREAM_EVENT_METRICS_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment