Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/common/include/launchdarkly/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum class Error : std::uint32_t {
/* Client-side errors: 10000-19999 */
/* Server-side errors: 20000-29999 */
kConfig_DataSystem_LazyLoad_MissingSource = 20000,
kConfig_BigSegments_NullStore = 20001,
kMax = std::numeric_limits<std::uint32_t>::max()
};

Expand Down
2 changes: 2 additions & 0 deletions libs/common/src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ char const* ErrorToString(Error err) {
return "sdk key: cannot be empty";
case Error::kConfig_DataSystem_LazyLoad_MissingSource:
return "data system: lazy load config requires a source";
case Error::kConfig_BigSegments_NullStore:
return "big segments: store must not be null";
case Error::kMax:
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#include <launchdarkly/connection.hpp>

#include <functional>
#include <memory>
#include <ostream>

namespace launchdarkly::server_side {

/**
* The current health of a Big Segments store, independent of any single
* context's membership.
*/
class BigSegmentStoreStatus {
public:
BigSegmentStoreStatus(bool available, bool stale);

/**
* True if the most recent store query or metadata poll succeeded. If false,
* Big Segments membership cannot currently be evaluated reliably.
*/
[[nodiscard]] bool IsAvailable() const;

/**
* True if the store's data has not been updated within the configured
* stale-after threshold. The data may still be queried; it is just older
* than desired.
*/
[[nodiscard]] bool IsStale() const;

private:
bool available_;
bool stale_;
};

bool operator==(BigSegmentStoreStatus const& a, BigSegmentStoreStatus const& b);
bool operator!=(BigSegmentStoreStatus const& a, BigSegmentStoreStatus const& b);

/**
* Interface for accessing and listening to the Big Segments store status.
*/
class IBigSegmentStoreStatusProvider {
public:
/**
* The current status of the Big Segments store. If no store is configured,
* reports unavailable and not stale.
*/
[[nodiscard]] virtual BigSegmentStoreStatus Status() const = 0;

/**
* Listen to changes to the Big Segments store status. The handler is
* invoked only when the status changes, not on every metadata poll.
*
* @param handler Function which will be called with the new status.
* @return A IConnection which can be used to stop listening to the status.
*/
virtual std::unique_ptr<IConnection> OnBigSegmentStoreStatusChange(
std::function<void(BigSegmentStoreStatus status)> handler) = 0;

virtual ~IBigSegmentStoreStatusProvider() = default;
IBigSegmentStoreStatusProvider(IBigSegmentStoreStatusProvider const&) =
delete;
IBigSegmentStoreStatusProvider(IBigSegmentStoreStatusProvider&&) = delete;
IBigSegmentStoreStatusProvider& operator=(
IBigSegmentStoreStatusProvider const&) = delete;
IBigSegmentStoreStatusProvider& operator=(
IBigSegmentStoreStatusProvider&&) = delete;

protected:
IBigSegmentStoreStatusProvider() = default;
};

std::ostream& operator<<(std::ostream& out,
BigSegmentStoreStatus const& status);

} // namespace launchdarkly::server_side
29 changes: 21 additions & 8 deletions libs/server-sdk/include/launchdarkly/server_side/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <launchdarkly/value.hpp>

#include <launchdarkly/server_side/all_flags_state.hpp>
#include <launchdarkly/server_side/big_segment_store_status.hpp>
#include <launchdarkly/server_side/data_source_status.hpp>

#include <chrono>
Expand Down Expand Up @@ -277,10 +278,11 @@ class IClient {
* @return The variation for the selected context, or default_value if the
* flag is disabled in the LaunchDarkly control panel
*/
virtual std::string StringVariation(Context const& ctx,
FlagKey const& key,
std::string default_value,
hooks::HookContext const& hook_context) = 0;
virtual std::string StringVariation(
Context const& ctx,
FlagKey const& key,
std::string default_value,
hooks::HookContext const& hook_context) = 0;

/**
* Returns the string value of a feature flag for a given flag key, in an
Expand Down Expand Up @@ -499,6 +501,14 @@ class IClient {
*/
virtual IDataSourceStatusProvider& DataSourceStatus() = 0;

/**
* Returns an interface for querying the status of a Big Segment store and
* subscribing to status changes. If Big Segments are not configured, the
* provider reports the store as unavailable.
* @return A Big Segment store status provider.
*/
virtual IBigSegmentStoreStatusProvider& BigSegmentStoreStatus() = 0;

virtual ~IClient() = default;
IClient(IClient const& item) = delete;
IClient(IClient&& item) = delete;
Expand Down Expand Up @@ -574,10 +584,11 @@ class Client : public IClient {
FlagKey const& key,
std::string default_value) override;

std::string StringVariation(Context const& ctx,
FlagKey const& key,
std::string default_value,
hooks::HookContext const& hook_context) override;
std::string StringVariation(
Context const& ctx,
FlagKey const& key,
std::string default_value,
hooks::HookContext const& hook_context) override;

EvaluationDetail<std::string> StringVariationDetail(
Context const& ctx,
Expand Down Expand Up @@ -650,6 +661,8 @@ class Client : public IClient {

IDataSourceStatusProvider& DataSourceStatus() override;

IBigSegmentStoreStatusProvider& BigSegmentStoreStatus() override;

/**
* Returns the version of the SDK.
* @return String representing version of the SDK.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <launchdarkly/server_side/config/builders/data_system/data_system_builder.hpp>
#include <launchdarkly/server_side/config/builders/data_system/lazy_load_builder.hpp>

#include <launchdarkly/server_side/config/builders/big_segments_builder.hpp>

namespace launchdarkly::server_side::config::builders {

using SDK = launchdarkly::config::shared::ServerSDK;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#include <launchdarkly/server_side/config/built/big_segments_config.hpp>
#include <launchdarkly/server_side/integrations/big_segments/ibig_segment_store.hpp>

#include <launchdarkly/error.hpp>

#include <tl/expected.hpp>

#include <chrono>
#include <cstddef>
#include <memory>
Expand Down Expand Up @@ -68,12 +72,14 @@ class BigSegmentsBuilder {
/**
* @brief Resolves the configuration.
*
* Returns an error if the store passed to the constructor was null.
*
* If the configured @ref StatusPollInterval exceeds @ref StaleAfter,
* the poll interval in the returned config is clamped to the
* stale-after value so the SDK can detect staleness within one poll
* cycle.
*/
[[nodiscard]] built::BigSegmentsConfig Build() const;
[[nodiscard]] tl::expected<built::BigSegmentsConfig, Error> Build() const;

private:
std::shared_ptr<integrations::IBigSegmentStore> store_;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#pragma once

#include <launchdarkly/server_side/config/built/all_built.hpp>
#include <launchdarkly/server_side/config/built/big_segments_config.hpp>
#include <launchdarkly/server_side/config/built/data_system/data_system_config.hpp>
#include <launchdarkly/server_side/hooks/hook.hpp>

#include <memory>
#include <optional>
#include <vector>

namespace launchdarkly::server_side {
Expand All @@ -17,6 +19,7 @@ struct Config {
config::built::Events events,
std::optional<std::string> application_tag,
config::built::DataSystemConfig data_system_config,
std::optional<config::built::BigSegmentsConfig> big_segments,
config::built::HttpProperties http_properties,
std::vector<std::shared_ptr<hooks::Hook>> hooks);

Expand All @@ -31,6 +34,13 @@ struct Config {

config::built::DataSystemConfig const& DataSystemConfig() const;

/**
* The Big Segments configuration, or nullopt if Big Segments were not
* enabled via ConfigBuilder::BigSegments.
*/
[[nodiscard]] std::optional<config::built::BigSegmentsConfig> const&
BigSegments() const;

[[nodiscard]] config::built::HttpProperties const& HttpProperties() const;

[[nodiscard]] config::built::Logging const& Logging() const;
Expand All @@ -46,6 +56,7 @@ struct Config {
std::optional<std::string> application_tag_;
config::built::Events events_;
config::built::DataSystemConfig data_system_config_;
std::optional<config::built::BigSegmentsConfig> big_segments_;
config::built::HttpProperties http_properties_;
std::vector<std::shared_ptr<hooks::Hook>> hooks_;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <launchdarkly/server_side/hooks/hook.hpp>

#include <memory>
#include <optional>
#include <vector>

namespace launchdarkly::server_side {
Expand Down Expand Up @@ -50,6 +51,16 @@ class ConfigBuilder {
*/
config::builders::DataSystemBuilder& DataSystem();

/**
* Configures the SDK's Big Segments behavior. Pass a BigSegmentsBuilder
* constructed with the Big Segments store to use. If never called, Big
* Segments are not enabled and flags referencing them evaluate as if the
* context were not a member.
* @param builder A configured BigSegmentsBuilder.
* @return Reference to this.
*/
ConfigBuilder& BigSegments(config::builders::BigSegmentsBuilder builder);

/**
* Sets the SDK's networking configuration, using an HttpPropertiesBuilder.
* The builder has methods for setting individual HTTP-related properties.
Expand Down Expand Up @@ -99,6 +110,7 @@ class ConfigBuilder {
config::builders::AppInfoBuilder app_info_builder_;
config::builders::EventsBuilder events_builder_;
config::builders::DataSystemBuilder data_system_builder_;
std::optional<config::builders::BigSegmentsBuilder> big_segments_builder_;
config::builders::HttpPropertiesBuilder http_properties_builder_;
config::builders::LoggingBuilder logging_config_builder_;
std::vector<std::shared_ptr<hooks::Hook>> hooks_;
Expand Down
3 changes: 3 additions & 0 deletions libs/server-sdk/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ target_sources(${LIBNAME}
client.cpp
client_impl.cpp
data_source_status.cpp
big_segment_store_status.cpp
instance_id.hpp
instance_id.cpp
config/config.cpp
Expand Down Expand Up @@ -49,6 +50,8 @@ target_sources(${LIBNAME}
data_components/big_segments/membership_cache.cpp
data_components/big_segments/big_segment_store_wrapper.hpp
data_components/big_segments/big_segment_store_wrapper.cpp
data_components/big_segments/big_segment_store_status_provider.hpp
data_components/big_segments/big_segment_store_status_provider.cpp
data_interfaces/destination/itransactional_destination.hpp
data_components/memory_store/memory_store.hpp
data_components/memory_store/memory_store.cpp
Expand Down
34 changes: 34 additions & 0 deletions libs/server-sdk/src/big_segment_store_status.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <launchdarkly/server_side/big_segment_store_status.hpp>

namespace launchdarkly::server_side {

BigSegmentStoreStatus::BigSegmentStoreStatus(bool const available,
bool const stale)
: available_(available), stale_(stale) {}

bool BigSegmentStoreStatus::IsAvailable() const {
return available_;
}

bool BigSegmentStoreStatus::IsStale() const {
return stale_;
}

bool operator==(BigSegmentStoreStatus const& a,
BigSegmentStoreStatus const& b) {
return a.IsAvailable() == b.IsAvailable() && a.IsStale() == b.IsStale();
}

bool operator!=(BigSegmentStoreStatus const& a,
BigSegmentStoreStatus const& b) {
return !(a == b);
}

std::ostream& operator<<(std::ostream& out,
BigSegmentStoreStatus const& status) {
out << "BigSegmentStoreStatus(available=" << std::boolalpha
<< status.IsAvailable() << ", stale=" << status.IsStale() << ")";
return out;
}

} // namespace launchdarkly::server_side
9 changes: 6 additions & 3 deletions libs/server-sdk/src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ std::string Client::StringVariation(Context const& ctx,
std::string default_value,
hooks::HookContext const& hook_context) {
return client->StringVariation(ctx, key, std::move(default_value),
hook_context);
hook_context);
}

EvaluationDetail<std::string> Client::StringVariationDetail(
Expand Down Expand Up @@ -166,8 +166,7 @@ EvaluationDetail<double> Client::DoubleVariationDetail(
FlagKey const& key,
double default_value,
hooks::HookContext const& hook_context) {
return client->DoubleVariationDetail(ctx, key, default_value,
hook_context);
return client->DoubleVariationDetail(ctx, key, default_value, hook_context);
}

int Client::IntVariation(Context const& ctx,
Expand Down Expand Up @@ -230,6 +229,10 @@ IDataSourceStatusProvider& Client::DataSourceStatus() {
return client->DataSourceStatus();
}

IBigSegmentStoreStatusProvider& Client::BigSegmentStoreStatus() {
return client->BigSegmentStoreStatus();
}

char const* Client::Version() {
return kVersion;
}
Expand Down
Loading
Loading