Skip to content

Commit

Permalink
[RBD] Allow FetchDiscountWorker to load all active carts.
Browse files Browse the repository at this point in the history
Change-Id: I3408c16b55fb260ea2cbb3c24377f6a595ac4b7c
Bug: 1196024
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2847842
Commit-Queue: Mei Liang <meiliang@chromium.org>
Reviewed-by: David Trainor <dtrainor@chromium.org>
Reviewed-by: Calder Kitagawa <ckitagawa@chromium.org>
Cr-Commit-Position: refs/heads/master@{#881278}
  • Loading branch information
Mei Liang authored and Chromium LUCI CQ committed May 10, 2021
1 parent 8b01106 commit 6b5ea7c
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 65 deletions.
3 changes: 2 additions & 1 deletion chrome/browser/cart/cart_discount_fetcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,6 @@ void CartDiscountFetcher::OnDiscountsAvailable(
CartDiscountFetcherCallback callback,
std::unique_ptr<EndpointResponse> responses) {
// TODO(meiliang): parse response;
std::move(callback).Run();
CartDiscountMap result;
std::move(callback).Run(std::move(result));
}
11 changes: 10 additions & 1 deletion chrome/browser/cart/cart_discount_fetcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
#define CHROME_BROWSER_CART_CART_DISCOUNT_FETCHER_H_

#include <memory>
#include <unordered_map>

#include "base/memory/scoped_refptr.h"
#include "chrome/browser/cart/cart_db.h"
#include "chrome/browser/cart/cart_db_content.pb.h"
#include "chrome/browser/endpoint_fetcher/endpoint_fetcher.h"

namespace network {
Expand All @@ -15,7 +18,13 @@ class PendingSharedURLLoaderFactory;

class CartDiscountFetcher {
public:
using CartDiscountFetcherCallback = base::OnceCallback<void(void)>;
// base::flat_map is used here for optimization, since the number of carts are
// expected to be low (< 100) at this stage. Need to use std::map when number
// gets larger.
using CartDiscountMap =
base::flat_map<std::string, std::vector<cart_db::DiscountInfoProto>>;

using CartDiscountFetcherCallback = base::OnceCallback<void(CartDiscountMap)>;

virtual ~CartDiscountFetcher();

Expand Down
139 changes: 110 additions & 29 deletions chrome/browser/cart/fetch_discount_worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,64 +14,145 @@
namespace {
// TODO(meiliang): Make it configurable via finch parameter.
// 30 minutes.
const int64_t DELAY_WORK_MS = 1800000;
const int64_t kDelayFetchMs = 1800000;
const int kImmediateFetchMs = 0;

} // namespace

CartLoader::CartLoader(Profile* profile)
: cart_service_(CartServiceFactory::GetForProfile(profile)) {}

CartLoader::~CartLoader() = default;

void CartLoader::LoadAllCarts(CartDB::LoadCallback callback) {
cart_service_->LoadAllActiveCarts(std::move(callback));
}

CartDiscountUpdater::CartDiscountUpdater(Profile* profile)
: cart_service_(CartServiceFactory::GetForProfile(profile)) {}

CartDiscountUpdater::~CartDiscountUpdater() = default;

void CartDiscountUpdater::update() {}

CartLoaderAndUpdaterFactory::CartLoaderAndUpdaterFactory(Profile* profile)
: profile_(profile) {}

CartLoaderAndUpdaterFactory::~CartLoaderAndUpdaterFactory() = default;

std::unique_ptr<CartLoader> CartLoaderAndUpdaterFactory::createCartLoader() {
return std::make_unique<CartLoader>(profile_);
}

std::unique_ptr<CartDiscountUpdater>
CartLoaderAndUpdaterFactory::createCartDiscountUpdater() {
return std::make_unique<CartDiscountUpdater>(profile_);
}

FetchDiscountWorker::FetchDiscountWorker(
scoped_refptr<network::SharedURLLoaderFactory>
browserProcessURLLoaderFactory,
std::unique_ptr<CartDiscountFetcherFactory> fetcher_factory)
std::unique_ptr<CartDiscountFetcherFactory> fetcher_factory,
std::unique_ptr<CartLoaderAndUpdaterFactory>
cart_loader_and_updater_factory)
: browserProcessURLLoaderFactory_(browserProcessURLLoaderFactory),
fetcher_factory_(std::move(fetcher_factory)) {
fetcher_factory_(std::move(fetcher_factory)),
cart_loader_and_updater_factory_(
std::move(cart_loader_and_updater_factory)) {
backend_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
{base::TaskPriority::BEST_EFFORT});
}

FetchDiscountWorker::~FetchDiscountWorker() = default;

void FetchDiscountWorker::Start() {
PostDiscountFetchTask(0);
void FetchDiscountWorker::Start(base::TimeDelta delay) {
// Post a delay task to avoid an infinite loop for creating the CartService.
// Since CartLoader and CartDiscountUpdater both depend on CartService.
content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
->PostDelayedTask(
FROM_HERE,
base::BindOnce(&FetchDiscountWorker::PrepareToFetch,
weak_ptr_factory_.GetWeakPtr(), kImmediateFetchMs),
delay);
}

void FetchDiscountWorker::PostDiscountFetchTask(int delay_work_ms) {
void FetchDiscountWorker::PrepareToFetch(unsigned int delay_fetch_ms) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

auto pending_factory = browserProcessURLLoaderFactory_->Clone();
// Load all active carts.
auto cart_loaded_callback =
base::BindOnce(&FetchDiscountWorker::ReadyToFetch,
weak_ptr_factory_.GetWeakPtr(), delay_fetch_ms);
auto loader = cart_loader_and_updater_factory_->createCartLoader();
loader->LoadAllCarts(std::move(cart_loaded_callback));
}

auto continue_to_work_callback =
base::BindOnce(&FetchDiscountWorker::PostDiscountFetchTask,
weak_ptr_factory_.GetWeakPtr(), DELAY_WORK_MS);
void FetchDiscountWorker::ReadyToFetch(
int delay_fetch_ms,
bool success,
std::vector<CartDB::KeyAndValue> proto_pairs) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

std::unique_ptr<CartDiscountFetcher> fetcher =
fetcher_factory_->createFetcher();
auto pending_factory = browserProcessURLLoaderFactory_->Clone();
auto fetcher = fetcher_factory_->createFetcher();
auto done_fetching_callback =
base::BindOnce(&FetchDiscountWorker::AfterDiscountFetched,
weak_ptr_factory_.GetWeakPtr());

backend_task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DoWorkInBackground, std::move(pending_factory),
std::move(fetcher), std::move(continue_to_work_callback)),
base::TimeDelta::FromMilliseconds(delay_work_ms));
base::BindOnce(&FetchInBackground, std::move(pending_factory),
std::move(fetcher), std::move(done_fetching_callback)),
base::TimeDelta::FromMilliseconds(delay_fetch_ms));
}

void FetchDiscountWorker::DoWorkInBackground(
void FetchDiscountWorker::FetchInBackground(
std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory,
std::unique_ptr<CartDiscountFetcher> fetcher,
ContinueToWorkCallback continue_to_work_callback) {
AfterFetchingCallback after_fetching_callback) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

auto on_work_finished_callback =
base::BindOnce(&OnWorkFinished, std::move(continue_to_work_callback));

// TODO(meiliang): load carts and call fetcher to get discounts for carts
// CartDiscountFetcher fetcher;
fetcher->Fetch(std::move(pending_factory),
std::move(on_work_finished_callback));
auto done_fetching_callback = base::BindOnce(
&DoneFetchingInBackground, std::move(after_fetching_callback));
fetcher->Fetch(std::move(pending_factory), std::move(done_fetching_callback));
}

void FetchDiscountWorker::OnWorkFinished(
ContinueToWorkCallback continue_to_work_callback) {
// TODO(meiliang): Follow up to use BindPostTask.
void FetchDiscountWorker::DoneFetchingInBackground(
AfterFetchingCallback after_fetching_callback,
CartDiscountFetcher::CartDiscountMap discounts) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// TODO(meiliang): Load and update carts with discount.

content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, std::move(continue_to_work_callback));
content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
->PostTask(FROM_HERE,
base::BindOnce(
[](AfterFetchingCallback callback,
CartDiscountFetcher::CartDiscountMap map) {
std::move(callback).Run(std::move(map));
},
std::move(after_fetching_callback), std::move(discounts)));
}

void FetchDiscountWorker::AfterDiscountFetched(
CartDiscountFetcher::CartDiscountMap discounts) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

auto update_discount_callback =
base::BindOnce(&FetchDiscountWorker::OnUpdatingDiscounts,
weak_ptr_factory_.GetWeakPtr(), std::move(discounts));
auto loader = cart_loader_and_updater_factory_->createCartLoader();
loader->LoadAllCarts(std::move(update_discount_callback));
}

void FetchDiscountWorker::OnUpdatingDiscounts(
CartDiscountFetcher::CartDiscountMap discounts,
bool success,
std::vector<CartDB::KeyAndValue> proto_pairs) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

// TODO(meiliang): Iterate over |proto_pairs| and update it based on
// |discounts|.

// Continue to work
PrepareToFetch(kDelayFetchMs);
}
106 changes: 84 additions & 22 deletions chrome/browser/cart/fetch_discount_worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,75 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/cart/cart_discount_fetcher.h"
#include "chrome/browser/cart/cart_service.h"

namespace network {
class SharedURLLoaderFactory;
class PendingSharedURLLoaderFactory;
} // namespace network

class CartLoader {
public:
explicit CartLoader(Profile* profile);
virtual ~CartLoader();
virtual void LoadAllCarts(CartDB::LoadCallback callback);

private:
CartService* cart_service_;
};

class CartDiscountUpdater {
public:
explicit CartDiscountUpdater(Profile* profile);
virtual ~CartDiscountUpdater();
virtual void update();

private:
CartService* cart_service_;
};

class CartLoaderAndUpdaterFactory {
public:
// TODO(crbug.com/1207197): Investigate to pass in Cartservice directly.
explicit CartLoaderAndUpdaterFactory(Profile* profile);
virtual ~CartLoaderAndUpdaterFactory();
virtual std::unique_ptr<CartLoader> createCartLoader();
virtual std::unique_ptr<CartDiscountUpdater> createCartDiscountUpdater();

private:
Profile* profile_;
};

// This is used to fetch discounts for active Carts in cart_db. It starts
// to work after calling #Start and continue to work util Chrome is finished.
// to work after calling Start() and continue to work util Chrome is finished.
// The flow looks as follow:
// Start()
// |
// V
// PostDiscountFetchTask() <----
// | |
// V |
// DoWorkInBackground() |
// | |
// V |
// OnWorkFinished() -----------
//
// UI Thread | backend_task_runner_
// ===========================================
// 1) PrepareToFetch |
// 2) ReadyToFetch |
// 3) | FetchInBackground
// 4) | DoneFetchingInBackground
// 5) AfterDiscountFetched |
// 6) OnUpdatingDiscounts |
// 7) Restart PrepareToFetch|

// TODO(meiliang): Add an API to allow ending the work earlier. e.g. when user
// has hidden the cart module.
class FetchDiscountWorker {
public:
FetchDiscountWorker(
scoped_refptr<network::SharedURLLoaderFactory>
browserProcessURLLoaderFactory,
std::unique_ptr<CartDiscountFetcherFactory> fetcher_factory);
std::unique_ptr<CartDiscountFetcherFactory> fetcher_factory,
std::unique_ptr<CartLoaderAndUpdaterFactory> cartLoaderAndUpdaterFactory);
~FetchDiscountWorker();
// Starts the worker to work.
void Start();
void Start(base::TimeDelta delay);

private:
using AfterFetchingCallback =
base::OnceCallback<void(CartDiscountFetcher::CartDiscountMap)>;
using ContinueToWorkCallback = base::OnceCallback<void()>;

scoped_refptr<network::SharedURLLoaderFactory>
Expand All @@ -50,18 +86,44 @@ class FetchDiscountWorker {
scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
// This is used to create a CartDiscountFetcher to fetch discounts.
std::unique_ptr<CartDiscountFetcherFactory> fetcher_factory_;
// This is used to create CartLoader to load all active carts, and
// CartDiscountUpdater to update the given cart discount.
std::unique_ptr<CartLoaderAndUpdaterFactory> cart_loader_and_updater_factory_;

// Posts the discount fetching work to another thread as a delayed background
// task. This method is expected to run in the UI thread.
void PostDiscountFetchTask(int delayTime);
// Performs the actual fetching work.
static void DoWorkInBackground(
// This is run in the UI thread, it creates a `CartLoader` and loads all
// active carts.
void PrepareToFetch(unsigned int delay_fetch_ms);

// This is run in the UI thread, it posts the discount fetching work,
// FetchInBackground(), to another thread as a delayed background task.
void ReadyToFetch(int delay_work_ms,
bool success,
std::vector<CartDB::KeyAndValue> proto_pairs);

// TODO(crbug.com/1207197): Change these two static method to anonymous
// namespace in the cc file. This is run in a background thread, it fetches
// for discounts for all active carts.
static void FetchInBackground(
std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory,
std::unique_ptr<CartDiscountFetcher> fetcher,
ContinueToWorkCallback continue_to_work_callback);
// A callback to handle the fetching result. It also posts
// #PostDiscountFetchTask to the UI thread to continue working.
static void OnWorkFinished(ContinueToWorkCallback continue_to_work_callback);
AfterFetchingCallback after_fetching_callback);

// This is run in a background thread, it posts AfterDiscountFetched() back to
// UI thread to process the fetched result.
static void DoneFetchingInBackground(
AfterFetchingCallback after_fetching_callback,
CartDiscountFetcher::CartDiscountMap discounts);

// This is run in the UI thread, it loads all active carts to update its
// discount.
void AfterDiscountFetched(CartDiscountFetcher::CartDiscountMap discounts);

// This is run in the UI thread, it updates discounts for all the active
// carts. It also post PrepareToFetch() to continue fetching in the
// background.
void OnUpdatingDiscounts(CartDiscountFetcher::CartDiscountMap discounts,
bool success,
std::vector<CartDB::KeyAndValue> proto_pairs);

base::WeakPtrFactory<FetchDiscountWorker> weak_ptr_factory_{this};
};
Expand Down

0 comments on commit 6b5ea7c

Please sign in to comment.