Skip to content

Commit 4de5eaa

Browse files
authored
feat: implement event delivery (#29)
* feat: implement asynchronous event delivery
1 parent ba5c5ae commit 4de5eaa

31 files changed

+1046
-153
lines changed

libs/client-sdk/include/launchdarkly/client_side/api.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
#include "config/client.hpp"
1313
#include "context.hpp"
1414
#include "error.hpp"
15-
#include "events/event_processor.hpp"
1615
#include "launchdarkly/client_side/data_source.hpp"
1716
#include "launchdarkly/client_side/data_sources/detail/data_source_status_manager.hpp"
17+
#include "launchdarkly/client_side/event_processor.hpp"
1818
#include "launchdarkly/client_side/flag_manager/detail/flag_manager.hpp"
1919
#include "launchdarkly/client_side/flag_manager/detail/flag_updater.hpp"
2020
#include "logger.hpp"
@@ -25,6 +25,11 @@ class Client {
2525
public:
2626
Client(Config config, Context context);
2727

28+
Client(Client&&) = delete;
29+
Client(Client const&) = delete;
30+
Client& operator=(Client) = delete;
31+
Client& operator=(Client&& other) = delete;
32+
2833
using FlagKey = std::string;
2934
[[nodiscard]] std::unordered_map<FlagKey, Value> AllFlags() const;
3035

@@ -72,7 +77,7 @@ class Client {
7277
std::thread thread_;
7378
boost::asio::io_context ioc_;
7479
Context context_;
75-
std::unique_ptr<events::IEventProcessor> event_processor_;
80+
std::unique_ptr<IEventProcessor> event_processor_;
7681
std::unique_ptr<IDataSource> data_source_;
7782
std::thread run_thread_;
7883
};

libs/common/include/events/event_processor.hpp renamed to libs/client-sdk/include/launchdarkly/client_side/event_processor.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include "events/events.hpp"
44

5-
namespace launchdarkly::events {
5+
namespace launchdarkly::client_side {
66

77
class IEventProcessor {
88
public:
@@ -12,7 +12,7 @@ class IEventProcessor {
1212
* capacity.
1313
* @param event InputEvent to deliver.
1414
*/
15-
virtual void AsyncSend(InputEvent event) = 0;
15+
virtual void AsyncSend(events::InputEvent event) = 0;
1616
/**
1717
* Asynchronously flush's the processor's events, returning as soon as
1818
* possible. Flushing may be a no-op if a flush is ongoing.
@@ -34,4 +34,4 @@ class IEventProcessor {
3434
IEventProcessor() = default;
3535
};
3636

37-
} // namespace launchdarkly::events
37+
} // namespace launchdarkly::client_side
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
3+
#include <boost/asio/any_io_executor.hpp>
4+
#include "config/client.hpp"
5+
#include "config/detail/sdks.hpp"
6+
#include "events/detail/asio_event_processor.hpp"
7+
#include "launchdarkly/client_side/event_processor.hpp"
8+
#include "logger.hpp"
9+
10+
namespace launchdarkly::client_side::detail {
11+
12+
class EventProcessor : public IEventProcessor {
13+
public:
14+
EventProcessor(boost::asio::any_io_executor const& io,
15+
Config const& config,
16+
Logger& logger);
17+
void AsyncSend(events::InputEvent event) override;
18+
void AsyncFlush() override;
19+
void AsyncClose() override;
20+
21+
private:
22+
events::detail::AsioEventProcessor<SDK> impl_;
23+
};
24+
25+
} // namespace launchdarkly::client_side::detail
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
3+
#include "launchdarkly/client_side/event_processor.hpp"
4+
5+
namespace launchdarkly::client_side::detail {
6+
7+
class NullEventProcessor : public IEventProcessor {
8+
public:
9+
NullEventProcessor() = default;
10+
void AsyncSend(events::InputEvent event) override;
11+
void AsyncFlush() override;
12+
void AsyncClose() override;
13+
};
14+
} // namespace launchdarkly::client_side::detail

libs/client-sdk/src/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ file(GLOB HEADER_LIST CONFIGURE_DEPENDS
66
"${LaunchDarklyCPPClient_SOURCE_DIR}/include/launchdarkly/client_side/data_sources/detail/*.hpp"
77
"${LaunchDarklyCPPClient_SOURCE_DIR}/include/launchdarkly/client_side/flag_manager/*.hpp"
88
"${LaunchDarklyCPPClient_SOURCE_DIR}/include/launchdarkly/client_side/flag_manager/detail/*.hpp"
9+
"${LaunchDarklyCPPClient_SOURCE_DIR}/include/launchdarkly/client_side/event_processor/*.hpp"
10+
"${LaunchDarklyCPPClient_SOURCE_DIR}/include/launchdarkly/client_side/event_processor/detail/*.hpp"
911
)
1012

1113
# Automatic library: static or dynamic based on user config.
@@ -23,6 +25,8 @@ add_library(${LIBNAME}
2325
flag_manager/flag_change_event.cpp
2426
data_sources/data_source_status.cpp
2527
data_sources/data_source_status_manager.cpp
28+
event_processor/event_processor.cpp
29+
event_processor/null_event_processor.cpp
2630
boost_signal_connection.cpp
2731
)
2832

libs/client-sdk/src/api.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
#include <optional>
44
#include <utility>
55

6-
#include "events/detail/asio_event_processor.hpp"
76
#include "launchdarkly/client_side/data_sources/detail/polling_data_source.hpp"
87
#include "launchdarkly/client_side/data_sources/detail/streaming_data_source.hpp"
8+
#include "launchdarkly/client_side/event_processor/detail/event_processor.hpp"
9+
#include "launchdarkly/client_side/event_processor/detail/null_event_processor.hpp"
910

1011
namespace launchdarkly::client_side {
1112

@@ -14,7 +15,7 @@ using launchdarkly::client_side::data_sources::DataSourceStatus;
1415
static std::unique_ptr<IDataSource> MakeDataSource(
1516
Config const& config,
1617
Context const& context,
17-
boost::asio::any_io_executor executor,
18+
boost::asio::any_io_executor const& executor,
1819
flag_manager::detail::FlagUpdater& flag_updater,
1920
data_sources::detail::DataSourceStatusManager& status_manager,
2021
Logger& logger) {
@@ -32,13 +33,7 @@ static std::unique_ptr<IDataSource> MakeDataSource(
3233
Client::Client(Config config, Context context)
3334
: logger_(config.Logger()),
3435
context_(std::move(context)),
35-
event_processor_(
36-
std::make_unique<launchdarkly::events::detail::AsioEventProcessor>(
37-
ioc_.get_executor(),
38-
config.Events(),
39-
config.ServiceEndpoints(),
40-
config.SdkKey(),
41-
logger_)),
36+
event_processor_(nullptr),
4237
flag_updater_(flag_manager_),
4338
data_source_(MakeDataSource(config,
4439
context_,
@@ -47,6 +42,15 @@ Client::Client(Config config, Context context)
4742
status_manager_,
4843
logger_)),
4944
initialized_(false) {
45+
if (config.Events().Enabled()) {
46+
event_processor_ = std::make_unique<detail::EventProcessor>(
47+
ioc_.get_executor(), config, logger_);
48+
} else {
49+
event_processor_ = std::make_unique<detail::NullEventProcessor>();
50+
}
51+
52+
data_source_->Start();
53+
5054
status_manager_.OnDataSourceStatusChange([this](auto status) {
5155
if (status.State() == DataSourceStatus::DataSourceState::kValid ||
5256
status.State() == DataSourceStatus::DataSourceState::kShutdown ||
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include "launchdarkly/client_side/event_processor/detail/event_processor.hpp"
2+
3+
namespace launchdarkly::client_side::detail {
4+
5+
EventProcessor::EventProcessor(boost::asio::any_io_executor const& io,
6+
Config const& config,
7+
Logger& logger)
8+
: impl_(io, config, logger) {}
9+
10+
void EventProcessor::AsyncSend(launchdarkly::events::InputEvent event) {
11+
impl_.AsyncSend(std::move(event));
12+
}
13+
14+
void EventProcessor::AsyncFlush() {
15+
impl_.AsyncFlush();
16+
}
17+
18+
void EventProcessor::AsyncClose() {
19+
impl_.AsyncClose();
20+
}
21+
22+
} // namespace launchdarkly::client_side::detail
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include "launchdarkly/client_side/event_processor/detail/null_event_processor.hpp"
2+
3+
namespace launchdarkly::client_side::detail {
4+
5+
void NullEventProcessor::AsyncSend(events::InputEvent event) {}
6+
7+
void NullEventProcessor::AsyncFlush() {}
8+
9+
void NullEventProcessor::AsyncClose() {}
10+
} // namespace launchdarkly::client_side::detail

libs/common/include/config/client.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ using AppInfoBuilder = config::detail::builders::AppInfoBuilder;
1616
using EndpointsBuilder = config::detail::builders::EndpointsBuilder<SDK>;
1717
using ConfigBuilder = config::detail::builders::ConfigBuilder<SDK>;
1818
using EventsBuilder = config::detail::builders::EventsBuilder<SDK>;
19+
using HttpPropertiesBuilder =
20+
config::detail::builders::HttpPropertiesBuilder<SDK>;
1921
using DataSourceBuilder = config::detail::builders::DataSourceBuilder<SDK>;
22+
2023
using Config = config::detail::Config<SDK>;
2124

2225
} // namespace launchdarkly::client_side

libs/common/include/config/detail/builders/events_builder.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ class EventsBuilder {
3434
*/
3535
EventsBuilder();
3636

37+
/**
38+
* Specify if event-sending should be enabled or not. By default,
39+
* events are enabled.
40+
* @param enabled True to enable.
41+
* @return Reference to this builder.
42+
*/
43+
EventsBuilder& Enabled(bool enabled);
44+
45+
/**
46+
* Alias for Enabled(false).
47+
* @return Reference to this builder.
48+
*/
49+
EventsBuilder& Disable();
50+
3751
/**
3852
* Sets the capacity of the event processor. When more events are generated
3953
* within the processor's flush interval than this value, events will be

libs/common/include/config/detail/built/events.hpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class Events final {
1919
friend class builders::EventsBuilder;
2020
/**
2121
* Constructs configuration for the event subsystem.
22+
* @param enabled If event-sending is enabled. If false, no events will be
23+
* sent to LaunchDarkly.
2224
* @param capacity How many events can queue in memory before new events
2325
* are dropped.
2426
* @param flush_interval How often events are automatically flushed to
@@ -31,12 +33,22 @@ class Events final {
3133
* AllAttributesPrivate is false.
3234
* @param security Whether a plaintext or encrypted client should be used
3335
* for event delivery.
36+
* @param flush_workers How many workers to use for concurrent event
37+
* delivery.
3438
*/
35-
Events(std::size_t capacity,
39+
Events(bool enabled,
40+
std::size_t capacity,
3641
std::chrono::milliseconds flush_interval,
3742
std::string path,
3843
bool all_attributes_private,
39-
AttributeReference::SetType private_attrs);
44+
AttributeReference::SetType private_attrs,
45+
std::chrono::milliseconds delivery_retry_delay,
46+
std::size_t flush_workers);
47+
48+
/**
49+
* Returns true if event-sending is enabled.
50+
*/
51+
[[nodiscard]] bool Enabled() const;
4052

4153
/**
4254
* Capacity of the event processor.
@@ -48,6 +60,12 @@ class Events final {
4860
*/
4961
[[nodiscard]] std::chrono::milliseconds FlushInterval() const;
5062

63+
/*
64+
* If an event payload fails to be delivered and can be retried, how long
65+
* to wait before retrying.
66+
*/
67+
[[nodiscard]] std::chrono::milliseconds DeliveryRetryDelay() const;
68+
5169
/**
5270
* Path component of the LaunchDarkly event delivery endpoint.
5371
*/
@@ -63,12 +81,20 @@ class Events final {
6381
*/
6482
[[nodiscard]] AttributeReference::SetType const& PrivateAttributes() const;
6583

84+
/**
85+
* Number of flush workers used for concurrent event delivery.
86+
*/
87+
[[nodiscard]] std::size_t FlushWorkers() const;
88+
6689
private:
90+
bool enabled_;
6791
std::size_t capacity_;
6892
std::chrono::milliseconds flush_interval_;
6993
std::string path_;
7094
bool all_attributes_private_;
7195
AttributeReference::SetType private_attributes_;
96+
std::chrono::milliseconds delivery_retry_delay_;
97+
std::size_t flush_workers_;
7298
};
7399

74100
bool operator==(Events const& lhs, Events const& rhs);

libs/common/include/config/detail/defaults.hpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,14 @@ struct Defaults<ClientSDK> {
3535
}
3636

3737
static auto Events() -> built::Events {
38-
return {100, std::chrono::seconds(30), "/mobile", false,
39-
AttributeReference::SetType()};
38+
return {true,
39+
100,
40+
std::chrono::seconds(30),
41+
"/mobile",
42+
false,
43+
AttributeReference::SetType(),
44+
std::chrono::seconds(1),
45+
5};
4046
}
4147

4248
static auto HttpProperties() -> built::HttpProperties {
@@ -74,8 +80,14 @@ struct Defaults<ServerSDK> {
7480
}
7581

7682
static auto Events() -> built::Events {
77-
return {10000, std::chrono::seconds(5), "/bulk", false,
78-
AttributeReference::SetType()};
83+
return {true,
84+
10000,
85+
std::chrono::seconds(5),
86+
"/bulk",
87+
false,
88+
AttributeReference::SetType(),
89+
std::chrono::seconds(1),
90+
5};
7991
}
8092

8193
static auto HttpProperties() -> built::HttpProperties {

libs/common/include/config/server.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ using AppInfoBuilder = config::detail::builders::AppInfoBuilder;
1616
using EndpointsBuilder = config::detail::builders::EndpointsBuilder<SDK>;
1717
using ConfigBuilder = config::detail::builders::ConfigBuilder<SDK>;
1818
using EventsBuilder = config::detail::builders::EventsBuilder<SDK>;
19+
using HttpPropertiesBuilder =
20+
config::detail::builders::HttpPropertiesBuilder<SDK>;
1921
using DataSourceBuilder = config::detail::builders::DataSourceBuilder<SDK>;
2022

2123
using Config = config::detail::Config<SDK>;

0 commit comments

Comments
 (0)