Skip to content

Commit 9a3737d

Browse files
cwaldren-ldkeelerm84mmrjkinyoklion
authored
feat: server-side data system (#304)
This feature branch contains the server-side Data System implementation. This system allows the server-side SDK to operate within two paradigms: that of a background connection that streams data from LaunchDarkly, or a connection to a database mediated by an in-memory caching algorithm. --------- Co-authored-by: Matthew M. Keeler <[email protected]> Co-authored-by: Molly <[email protected]> Co-authored-by: Ryan Lamb <[email protected]>
1 parent 44821a2 commit 9a3737d

File tree

158 files changed

+5584
-1747
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

158 files changed

+5584
-1747
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
name: 'C++ Server SDK / Redis Source Bug Report'
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: 'package: sdk/server-redis, bug'
6+
assignees: ''
7+
8+
---
9+
10+
**Is this a support request?**
11+
This issue tracker is maintained by LaunchDarkly SDK developers and is intended for feedback on the code in this
12+
library. If you're not sure whether the problem you are having is specifically related to this library, or to the
13+
LaunchDarkly service overall, it may be more appropriate to contact the LaunchDarkly support team; they can help to
14+
investigate the problem and will consult the SDK team if necessary. You can submit a support request by
15+
going [here](https://support.launchdarkly.com/) and clicking "submit a request", or by emailing
16+
17+
18+
Note that issues filed on this issue tracker are publicly accessible. Do not provide any private account information on
19+
your issues. If your problem is specific to your account, you should submit a support request as described above.
20+
21+
**Describe the bug**
22+
A clear and concise description of what the bug is.
23+
24+
**To reproduce**
25+
Steps to reproduce the behavior.
26+
27+
**Expected behavior**
28+
A clear and concise description of what you expected to happen.
29+
30+
**Logs**
31+
If applicable, add any log output related to your problem.
32+
To get more logs from the SDK, change the log level using environment variable `LD_LOG_LEVEL`. For example:
33+
34+
```
35+
LD_LOG_LEVEL=debug ./your-application
36+
```
37+
38+
**SDK version**
39+
The version of this SDK that you are using.
40+
41+
**Language version, developer tools**
42+
For instance, C++17 or C11. If you are using a language that requires a separate compiler, such as C, please include the
43+
name and version of the compiler too.
44+
45+
**OS/platform**
46+
For instance, Ubuntu 16.04, Windows 10, or Android 4.0.3. If your code is running in a browser, please also include the
47+
browser type and version.
48+
49+
**Additional context**
50+
Add any other context about the problem here.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: 'C++ Server SDK / Redis Source Feature Request'
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: 'package: sdk/server-redis, feature'
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I would love to see the SDK [...does something new...]
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context about the feature request here.

.github/workflows/manual-publish-doc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
options:
1010
- libs/client-sdk
1111
- libs/server-sdk
12+
- libs/server-sdk-redis-source
1213
name: Publish Documentation
1314
jobs:
1415
build-publish:

.github/workflows/manual-sdk-release-artifacts.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ on:
1515
options:
1616
- libs/client-sdk:launchdarkly-cpp-client
1717
- libs/server-sdk:launchdarkly-cpp-server
18+
- libs/server-sdk-redis-source:launchdarkly-cpp-server-redis-source
1819

1920
name: Publish SDK Artifacts
2021

.github/workflows/server-redis.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: libs/server-sdk-redis-source
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
paths-ignore:
7+
- '**.md' #Do not need to run CI for markdown changes.
8+
pull_request:
9+
branches: [ "main", "feat/**" ]
10+
paths-ignore:
11+
- '**.md'
12+
13+
jobs:
14+
build-test-redis:
15+
runs-on: ubuntu-22.04
16+
services:
17+
redis:
18+
image: redis
19+
ports:
20+
- 6379:6379
21+
steps:
22+
- uses: actions/checkout@v3
23+
- uses: ./.github/actions/ci
24+
with:
25+
cmake_target: launchdarkly-cpp-server-redis-source
26+
simulate_release: true
27+
build-redis-mac:
28+
runs-on: macos-12
29+
steps:
30+
- uses: actions/checkout@v3
31+
- uses: ./.github/actions/ci
32+
with:
33+
cmake_target: launchdarkly-cpp-server-redis-source
34+
platform_version: 12
35+
run_tests: false # TODO: figure out how to run Redis service on Mac
36+
build-test-redis-windows:
37+
runs-on: windows-2022
38+
steps:
39+
- uses: actions/checkout@v3
40+
- uses: ilammy/msvc-dev-cmd@v1
41+
- uses: ./.github/actions/ci
42+
env:
43+
BOOST_LIBRARY_DIR: 'C:\local\boost_1_81_0\lib64-msvc-14.3'
44+
BOOST_LIBRARYDIR: 'C:\local\boost_1_81_0\lib64-msvc-14.3'
45+
with:
46+
cmake_target: launchdarkly-cpp-server-redis-source
47+
platform_version: 2022
48+
toolset: msvc
49+
run_tests: false # TODO: figure out how to run Redis service on Windows

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ option(LD_DYNAMIC_LINK_OPENSSL
6161

6262
option(LD_BUILD_EXAMPLES "Build hello-world examples." ON)
6363

64+
option(LD_BUILD_REDIS_SUPPORT "Build redis support." OFF)
65+
6466
# If using 'make' as the build system, CMake causes the 'install' target to have a dependency on 'all', meaning
6567
# it will cause a full build. This disables that, allowing us to build piecemeal instead. This is useful
6668
# so that we only need to build the client or server for a given release (if only the client or server were affected.)
@@ -142,6 +144,11 @@ add_subdirectory(libs/common)
142144
add_subdirectory(libs/internal)
143145
add_subdirectory(libs/server-sent-events)
144146

147+
if (LD_BUILD_REDIS_SUPPORT)
148+
message("LaunchDarkly: building server-side redis support")
149+
add_subdirectory(libs/server-sdk-redis-source)
150+
endif ()
151+
145152
# Built as static or shared depending on LD_BUILD_SHARED_LIBS variable.
146153
# This target "links" in common, internal, and sse as object libraries.
147154
add_subdirectory(libs/client-sdk)

architecture/server_data_source_arch.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ classDiagram
115115
+SetError(StatusCodeType code, std::string message) void
116116
}
117117
118-
```
118+
```
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Server Data System Architecture
2+
3+
**Client's usage of the Data System**
4+
5+
```mermaid
6+
classDiagram
7+
direction TB
8+
Client --* IDataSystem
9+
Client --* DataSourceStatusManager
10+
IDataSystem <|-- LazyLoad
11+
IDataSystem <|-- BackgroundSync
12+
IStore <|-- IDataSystem
13+
14+
```
15+
16+
**Data System - Background Sync**
17+
18+
```mermaid
19+
20+
classDiagram
21+
direction TB
22+
23+
class BackgroundSync {
24+
}
25+
26+
IDataSystem <|-- BackgroundSync
27+
BackgroundSync --* IDataSynchronizer
28+
IDataDestination <|-- MemoryStore
29+
IStore <|-- MemoryStore
30+
IDataSynchronizer ..> ChangeNotifier
31+
BackgroundSync --* ChangeNotifier
32+
ChangeNotifier ..> IDataDestination: writes data updates to..
33+
ChangeNotifier ..> IStore: reads necessary data from (to calculate deltas)..
34+
BackgroundSync --* MemoryStore
35+
36+
```
37+
38+
In order to satisfy `IDataSystem`, the Background Sync system owns a Memory Store, a Change Notifier,
39+
and an `IDataSynchronizer`.
40+
41+
Because `IDataSystem` is an `IStore`, Background Sync provides pass-through methods to the Memory Store.
42+
43+
Meanwhile, data updates are received from LaunchDarkly via the `IDataSynchronizer`, and then forwarded into
44+
the `IDataSynchronizer`'s destination - which is a Change Notifier object owned by Background Sync.
45+
46+
The Change Notifier wants to read existing flag/segment data (`IStore`) to compare
47+
it to the data it receives from the synchronizer, and then:
48+
49+
- Send out change updates
50+
- Store the updated data (`IDestination`), while guarding against stale data
51+
52+
Because all flag/segment data is stored in memory, the Memory Store satisfies Change Notifier's `IStore`
53+
and `IDestination`
54+
dependencies.
55+
56+
**Data System - Lazy Load**
57+
58+
```mermaid
59+
60+
classDiagram
61+
direction TB
62+
63+
class LazyLoad {
64+
}
65+
66+
IDataSystem <|-- LazyLoad
67+
LazyLoad --* IDataReader
68+
LazyLoad --* MemoryStore
69+
LazyLoad --* ExpirationTracker
70+
LazyLoad --* ISerializedDataReader
71+
IDataReader <|-- JsonDeserializer: passes back data models
72+
JsonDeserializer ..> ISerializedDataReader: reads serialized data
73+
ISerializedDataReader <|-- Redis
74+
ISerializedDataReader <|-- OtherStores: e.g. DynamoDB, etc.
75+
76+
77+
```
78+
79+
In contrast to Background Sync, Lazy Load actively implements `IStore` by fetching data items from
80+
an `ISerializedDataReader`
81+
via `IDataReader` and placing them in a Memory Store cache.
82+
83+
Items are cached for a period of time after which they are considered stale and refreshed. This logic is implemented
84+
by the Expiration Tracker.
85+
86+
Currently, Lazy Load only supports JSON as a storage format.
87+
88+
In practice, the `IDataReader` is therefore a `JsonDeserializer`. Theoretically it could be swapped out for dealing with
89+
(for example) protobuf.
90+
91+
The `JsonDeserializer` sits in between the Lazy Load system and its `ISerializedDataReader`, intercepting requests.
92+
93+
For example, when it receives a request to get a flag `foo` it forwards that to `ISerializedDataReader`, receives a JSON
94+
string as a response,
95+
deserializes that into the SDK's data model, and passes it back to the Lazy Load system.

architecture/server_store_arch.md

Lines changed: 0 additions & 98 deletions
This file was deleted.

cmake/redis-plus-plus.cmake

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.11)
2+
3+
include(FetchContent)
4+
5+
6+
FetchContent_Declare(hiredis
7+
GIT_REPOSITORY https://github.com/redis/hiredis.git
8+
GIT_TAG 60e5075d4ac77424809f855ba3e398df7aacefe8
9+
GIT_SHALLOW TRUE
10+
SOURCE_DIR _deps/hiredis
11+
OVERRIDE_FIND_PACKAGE
12+
)
13+
14+
15+
FetchContent_MakeAvailable(hiredis)
16+
17+
include_directories(${CMAKE_CURRENT_BINARY_DIR}/_deps)
18+
19+
set(REDIS_PLUS_PLUS_BUILD_TEST OFF CACHE BOOL "" FORCE)
20+
21+
# 1.3.7 is the last release that works with FetchContent, due to a problem with CheckSymbolExists
22+
# when it tries to do feature detection on hiredis.
23+
FetchContent_Declare(redis-plus-plus
24+
GIT_REPOSITORY https://github.com/sewenew/redis-plus-plus.git
25+
GIT_TAG 1.3.7
26+
GIT_SHALLOW TRUE
27+
)
28+
29+
FetchContent_MakeAvailable(redis-plus-plus)

0 commit comments

Comments
 (0)