1
#include "source/extensions/tracers/datadog/event_scheduler.h"
2

            
3
#include <memory>
4
#include <utility>
5

            
6
#include "source/common/common/assert.h"
7

            
8
#include "nlohmann/json.hpp"
9

            
10
namespace Envoy {
11
namespace Extensions {
12
namespace Tracers {
13
namespace Datadog {
14

            
15
40
EventScheduler::EventScheduler(Event::Dispatcher& dispatcher) : dispatcher_(dispatcher) {}
16

            
17
EventScheduler::Cancel
18
EventScheduler::schedule_recurring_event(std::chrono::steady_clock::duration interval,
19
65
                                         std::function<void()> callback) {
20
65
  auto self = std::make_shared<Event::Timer*>();
21
  // Yes, a shared pointer to a pointer.
22
  //
23
  // Both the timer callback (argument to `createTimer`, below) and the returned
24
  // cancellation function need a handle to the `Event::Timer`. The timer
25
  // callback needs it so that it can reschedule the next round when the timer
26
  // fires (that's how this is a _recurring_ event). The cancellation function
27
  // needs it so that it can call `disableTimer` and remove the timer from
28
  // `timers_`.
29
  //
30
  // Since we don't have a handle to the `Event::Timer` until `createTimer`
31
  // returns, we need a "box" out of which the timer callback can extract the
32
  // created timer. We then put the `Event::Timer*` in the "box" after
33
  // `createTimer` returns the timer. `self` is the "box."
34
  //
35
  // The cancellation function returned by this function refers to the
36
  // `Event::Timer` via a raw pointer (as does the timer callback, indirectly).
37
  // The actual lifetime of the pointed-to `Event::Timer` is determined by its
38
  // presence in `timers_`. The `Event::TimerPtr` returned by `createTimer` is
39
  // moved into `timers_`.
40

            
41
65
  Event::TimerPtr timer = dispatcher_.createTimer([self, interval, callback = std::move(callback)] {
42
1
    (**self).enableTimer(std::chrono::duration_cast<std::chrono::milliseconds>(interval));
43
1
    callback();
44
1
  });
45

            
46
65
  Event::Timer* timer_raw = timer.get();
47
65
  *self = timer_raw;
48

            
49
65
  timers_.insert(std::move(timer));
50

            
51
65
  timer_raw->enableTimer(std::chrono::duration_cast<std::chrono::milliseconds>(interval));
52

            
53
67
  return [this, timer = timer_raw]() mutable {
54
67
    if (!timer) {
55
5
      return; // idempotent
56
5
    }
57

            
58
62
    timer->disableTimer();
59
62
    auto found = timers_.find(timer);
60
62
    RELEASE_ASSERT(found != timers_.end(),
61
62
                   "timer not found in registry of timers in Datadog::EventScheduler");
62
62
    timers_.erase(found);
63
62
    timer = nullptr;
64
62
  };
65
65
}
66

            
67
34
std::string EventScheduler::config() const { return config_json().dump(); }
68

            
69
35
const nlohmann::json& EventScheduler::config_json() const {
70
35
  static const nlohmann::json config = nlohmann::json::object({
71
35
      {"type", "Envoy::Extensions::Tracers::Datadog::EventScheduler"},
72
35
  });
73
35
  return config;
74
35
}
75

            
76
} // namespace Datadog
77
} // namespace Tracers
78
} // namespace Extensions
79
} // namespace Envoy