Skip to content
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ build-dynamic
build-static-debug
build-dynamic-debug
cmake-build-*
.cache

# For Macs..
.DS_Store
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once

#include <launchdarkly/data_model/fdv2_change.hpp>
#include <launchdarkly/data_sources/data_source_status_error_info.hpp>

#include <optional>
#include <string>
#include <variant>

namespace launchdarkly::server_side::data_interfaces {

/**
* Result returned by IFDv2Initializer::Run and IFDv2Synchronizer::Next.
*
* Mirrors Java's FDv2SourceResult.
*/
struct FDv2SourceResult {
using ErrorInfo = common::data_sources::DataSourceStatusErrorInfo;

/**
* A changeset was successfully received and is ready to apply.
*/
struct ChangeSet {
data_model::FDv2ChangeSet change_set;
/** If true, the server signaled that the client should fall back to
* FDv1. */
bool fdv1_fallback;
};

/**
* A transient error occurred; the source may recover.
*/
struct Interrupted {
ErrorInfo error;
bool fdv1_fallback;
};

/**
* A non-recoverable error occurred; the source should not be retried.
*/
struct TerminalError {
ErrorInfo error;
bool fdv1_fallback;
};

/**
* The source was closed cleanly (via Close()).
*/
struct Shutdown {};

/**
* The server sent a goodbye; the orchestrator should rotate sources.
*/
struct Goodbye {
std::optional<std::string> reason;
bool fdv1_fallback;
};

/**
* Next() returned because the timeout expired before a result arrived.
*/
struct Timeout {};

using Value = std::variant<ChangeSet, Interrupted, TerminalError, Shutdown,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nicer than the Java shenanigans.

Goodbye, Timeout>;

Value value;
};

} // namespace launchdarkly::server_side::data_interfaces
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include "fdv2_source_result.hpp"

#include <string>

namespace launchdarkly::server_side::data_interfaces {

/**
* Defines a one-shot data source that runs to completion and returns a single
* result. Used during the initialization phase of FDv2, before handing off to
* an IFDv2Synchronizer.
*/
class IFDv2Initializer {
public:
/**
* Run the initializer to completion. Blocks until a result is available.
* Called at most once per instance.
*
* Close() may be called from another thread to unblock Run(), in which
* case Run() returns FDv2SourceResult::Shutdown.
*/
virtual FDv2SourceResult Run() = 0;

/**
* Unblocks any in-progress Run() call, causing it to return
* FDv2SourceResult::Shutdown.
*/
virtual void Close() = 0;

/**
* @return A display-suitable name of the initializer.
*/
[[nodiscard]] virtual std::string const& Identity() const = 0;

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

protected:
IFDv2Initializer() = default;
};

} // namespace launchdarkly::server_side::data_interfaces
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once

#include "fdv2_source_result.hpp"

#include <launchdarkly/data_model/selector.hpp>

#include <chrono>
#include <string>

namespace launchdarkly::server_side::data_interfaces {

/**
* Defines a continuous data source that produces a stream of results. Used
* during the synchronization phase of FDv2, after initialization is complete.
*
* The stream is started lazily on the first call to Next(). The synchronizer
* runs until Close() is called.
*/
class IFDv2Synchronizer {
public:
/**
* Block until the next result is available or the timeout expires.
*
* On the first call, the synchronizer starts its underlying connection.
* Subsequent calls continue reading from the same connection.
*
* If the timeout expires before a result arrives, returns
* FDv2SourceResult::Timeout. The orchestrator uses this to evaluate
* fallback conditions.
*
* Close() may be called from another thread to unblock Next(), in which
* case Next() returns FDv2SourceResult::Shutdown.
*
* @param timeout Maximum time to wait for the next result.
* @param selector The selector to send with the request, reflecting any
* changesets applied since the previous call.
*/
virtual FDv2SourceResult Next(std::chrono::milliseconds timeout,
data_model::Selector selector) = 0;

/**
* Unblocks any in-progress Next() call, causing it to return
* FDv2SourceResult::Shutdown, and releases underlying resources.
*/
virtual void Close() = 0;

/**
* @return A display-suitable name of the synchronizer.
*/
[[nodiscard]] virtual std::string const& Identity() const = 0;

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

protected:
IFDv2Synchronizer() = default;
};

} // namespace launchdarkly::server_side::data_interfaces
Loading