refactor: implement fdv2 polling initializer / synchronizer#519
refactor: implement fdv2 polling initializer / synchronizer#519
Conversation
| std::move(**result)}}; | ||
| } | ||
| // Silently skip unknown kinds for forward-compatibility. | ||
| return std::nullopt; |
There was a problem hiding this comment.
This ends up with maybe a slightly different layer responsibility, but I think it is likely fine. I think Java returns it, and then it is discarded a layer up, but we aren't acting on it, so it doesn't really make a difference.
There was a problem hiding this comment.
Actually I am a bit concerned that we may be losing granularity of data source reporting. Though maybe we don't have that concern at the moment.
There was a problem hiding this comment.
I'm not sure what exactly you're asking here. The Java version seems to have a distinction between parsing and "translation" that isn't there in C++. This function doesn't return raw JSON, so there's nothing to be returned in this case.
I believe, technically, our spec says that this case should silently ignore the uknown kind, whereas the Java implementation logs a warning. I followed the spec, but I could add a warning here, if you'd prefer.
This is the only branch that returns std::nullopt, so callers could still technically distinguish this case, but I'm not sure what else we would do about it.
There was a problem hiding this comment.
So, the thing I am trying to get at here is that the protocol handler here knows about the types, where I expect 1 layer up from here to know the types. Or for this to take a mapper type interface.
The reason being is that theoretically a client and server can use the same protocol handler, but they get different model types.
Server has flag and segment, and client-side has a flag-eval. The protocol itself should be agnostic to these types theoretically. Then you report "hey we got a change to kind: potato", and the data source layer can be like "I don't support potato" and then discard it.
In the Java version it just remains as some kind of JsonElement until another layer knows how to handle it.
Another option though is a mapper. Where the handler takes a mapper, and then says "map this type for me" and if the mapper says it cannot handle it, then we also know to discard it.
Mapper approach:
const protocolHandler = internal.createProtocolHandler(
{ 'flag-eval': processFlagEval },
config.logger,
);
In regards to the log, I do tend to prefer a log, but one could argue about it being debug, or just once, or something. But that isn't the main concern. This layer knowing about the specific types is.
There was a problem hiding this comment.
I am making a note to handle this in a follow-up PR. I'm just worried about this PR getting too big and out of hand.
| } | ||
|
|
||
| boost::system::error_code ec; | ||
| auto parsed = boost::json::parse(*body, ec); |
There was a problem hiding this comment.
Maybe we could lift the parsing into a function or have its own type?
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 112c78e. Configure here.

This implements the C++ polling initializer and synchronizer.
I have rewritten this code substantially since the first round of reviews, mostly by hand.
Changes:
FDv2PollingInitializerandFDv2PollingSynchronizer.IFDv2InitializerandIFDv2Synchronizerinterfaces to be async.deleteboth classes without joining any threads.AsioRequester::Requestto use a more modern style that is more flexible in how it can be used.AsioRequesterasconstto make it more obvious that it's thread-safe.Caveats:
Previous description:
Note
Medium Risk
Introduces new FDv2 polling data path and converts FDv2 source interfaces to
Future-based async, which can affect orchestration flow and lifecycle/shutdown behavior. Also changes the Boost.Asio HTTP requester initiation style, so regressions could impact networking behavior and timeouts.Overview
Adds an FDv2 polling implementation:
FDv2PollingInitializerperforms a one-shot poll, andFDv2PollingSynchronizerrepeatedly polls with minimum-interval enforcement and timeout/close handling using the internalPromise/Futureutilities.Introduces a shared
FDv2ProtocolHandlerstate machine that accumulates FDv2 wire events into a completeFDv2ChangeSet(or emits typed protocol/JSON/server errors andGoodbye), with accompanying unit tests.Refactors FDv2 source interfaces (
IFDv2Initializer::Run,IFDv2Synchronizer::Next) to returnasync::Future<FDv2SourceResult>instead of blocking results, adds async helpers (kInlineExecutor,MakeFuture,async::Delay), and updatesAsioRequester::Request/Requester::Requestto beconstand useboost::asio::async_initiate.Reviewed by Cursor Bugbot for commit 4b02b67. Bugbot is set up for automated code reviews on this repo. Configure here.