1
#pragma once
2

            
3
#include "envoy/api/api.h"
4
#include "envoy/common/random_generator.h"
5
#include "envoy/config/core/v3/base.pb.h"
6
#include "envoy/event/deferred_deletable.h"
7
#include "envoy/init/manager.h"
8
#include "envoy/upstream/cluster_manager.h"
9

            
10
#include "source/common/common/backoff_strategy.h"
11
#include "source/common/common/empty_string.h"
12
#include "source/common/common/enum_to_int.h"
13
#include "source/common/config/remote_data_fetcher.h"
14
#include "source/common/init/target_impl.h"
15
#include "source/extensions/common/wasm/remote_async_datasource.h"
16

            
17
#include "absl/types/optional.h"
18

            
19
namespace Envoy {
20

            
21
/**
22
 * Callback for async data source.
23
 */
24
using AsyncDataSourceCb = std::function<void(const std::string&)>;
25

            
26
class RemoteAsyncDataProvider : public Event::DeferredDeletable,
27
                                public Config::DataFetcher::RemoteDataFetcherCallback,
28
                                public Logger::Loggable<Logger::Id::config> {
29
public:
30
  RemoteAsyncDataProvider(Upstream::ClusterManager& cm, Init::Manager& manager,
31
                          const envoy::config::core::v3::RemoteDataSource& source,
32
                          Event::Dispatcher& dispatcher, Random::RandomGenerator& random,
33
                          bool allow_empty, AsyncDataSourceCb&& callback);
34

            
35
38
  ~RemoteAsyncDataProvider() override {
36
38
    init_target_.ready();
37
38
    if (retry_timer_) {
38
38
      retry_timer_->disableTimer();
39
38
    }
40
38
  }
41

            
42
  // Config::DataFetcher::RemoteDataFetcherCallback
43
24
  void onSuccess(const std::string& data) override {
44
24
    callback_(data);
45
24
    init_target_.ready();
46
24
  }
47

            
48
  // Config::DataFetcher::RemoteDataFetcherCallback
49
28
  void onFailure(Config::DataFetcher::FailureReason failure) override {
50
28
    ENVOY_LOG(debug, "Failed to fetch remote data, failure reason: {}", enumToInt(failure));
51
28
    if (retries_remaining_-- == 0) {
52
13
      ENVOY_LOG(warn, "Retry limit exceeded for fetching data from remote data source.");
53
13
      if (allow_empty_) {
54
12
        callback_(EMPTY_STRING);
55
12
      }
56
      // We need to allow server startup to continue.
57
13
      init_target_.ready();
58
13
      return;
59
13
    }
60

            
61
15
    const auto retry_ms = std::chrono::milliseconds(backoff_strategy_->nextBackOffMs());
62
15
    ENVOY_LOG(debug, "Remote data provider will retry in {} ms.", retry_ms.count());
63
15
    retry_timer_->enableTimer(retry_ms);
64
15
  }
65

            
66
private:
67
52
  void start() { fetcher_->fetch(); }
68

            
69
  bool allow_empty_;
70
  AsyncDataSourceCb callback_;
71
  const Config::DataFetcher::RemoteDataFetcherPtr fetcher_;
72
  Init::TargetImpl init_target_;
73

            
74
  Event::TimerPtr retry_timer_;
75
  BackOffStrategyPtr backoff_strategy_;
76
  uint32_t retries_remaining_;
77
};
78

            
79
using RemoteAsyncDataProviderPtr = std::unique_ptr<RemoteAsyncDataProvider>;
80

            
81
} // namespace Envoy