Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: server-side SDK #160

Merged
merged 80 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
c417579
feat: add server-sdk subdirectory
cwaldren-ld Jun 12, 2023
c985539
chore: move ItemDescriptor to internal library (#151)
cwaldren-ld Jun 14, 2023
420d7a2
feat: update event processor to handle context key deduplication (#150)
cwaldren-ld Jun 14, 2023
4f89b44
chore: Merge branch 'main' into server-side
kinyoklion Jun 30, 2023
dd174a2
feat: segment data model (#153)
cwaldren-ld Jun 30, 2023
4954f88
feat: flag data model (#156)
cwaldren-ld Jun 30, 2023
f38e038
Merge branch 'main' into server-side
cwaldren-ld Jul 6, 2023
09d2bd6
feat: add Flag model to SDKDataSet (#159)
cwaldren-ld Jul 6, 2023
8367305
chore: Implement architecture diagram for data store. (#161)
kinyoklion Jul 7, 2023
2781af0
fix: Add various missing headers. (#163)
kinyoklion Jul 7, 2023
90627f2
chore: Implement server data source architecture diagram. (#167)
kinyoklion Jul 11, 2023
f2d96a4
feat: Implement basic in-memory store and change handling. (#165)
kinyoklion Jul 12, 2023
3c12979
chore: Refactor to allow sharing data source status and IDataSource. …
kinyoklion Jul 12, 2023
08aaa66
feat: Implement streaming data source. (#179)
kinyoklion Jul 17, 2023
3692736
chore: Update data store updater use reference. (#181)
kinyoklion Jul 17, 2023
ceec434
Merge branch 'main' into server-side
kinyoklion Jul 17, 2023
99dea86
feat: add ContextKind type to data model (#184)
cwaldren-ld Jul 18, 2023
e5992ef
feat: evaluation engine (#183)
cwaldren-ld Jul 18, 2023
bb75d4b
feat: initial pass of server-side Client object (#176)
cwaldren-ld Jul 19, 2023
674c343
feat: Add persistent store core interface. (#187)
kinyoklion Jul 19, 2023
0ead705
fix: EvaluationStack should take ownership of key argument (#190)
cwaldren-ld Jul 19, 2023
30d2e21
feat: Add expiration tracker. (#188)
kinyoklion Jul 19, 2023
213acbd
chore: add event processor architectural diagrams (#192)
cwaldren-ld Jul 20, 2023
0b29ea2
feat: Serialize flags and segments. (#194)
kinyoklion Jul 21, 2023
1f44309
Merge branch 'main' into server-side
cwaldren-ld Aug 16, 2023
a592e87
feat: build server SDK in CI (#198)
cwaldren-ld Aug 21, 2023
275bb66
feat: hello-cpp-server (#202)
cwaldren-ld Aug 23, 2023
9b38361
feat: server-side contract tests (#197)
cwaldren-ld Aug 23, 2023
57c29d8
fix: multi-kind user segment targeting (#206)
cwaldren-ld Aug 24, 2023
ef1061e
fix: handle undefined flag variations in fallthrough (#205)
cwaldren-ld Aug 24, 2023
648e202
Merge branch 'main' into server-side
cwaldren-ld Aug 24, 2023
9edacd1
Merge branch 'main' into server-side
cwaldren-ld Aug 25, 2023
09c74dd
remove contract test branch from server.yml
cwaldren-ld Aug 25, 2023
4ccd79f
fix: refactor Variation methods for correctness & clarity (#203)
cwaldren-ld Aug 25, 2023
a7a9660
Merge branch 'main' into server-side
cwaldren-ld Aug 25, 2023
9ec37f6
refactor: push typechecking of variation methods deeper down (#216)
cwaldren-ld Aug 28, 2023
30bfed2
Merge branch 'main' into server-side
cwaldren-ld Aug 28, 2023
62cb864
Merge branch 'main' into server-side
cwaldren-ld Aug 29, 2023
66b4c83
fix: deserializing certain values leads to infinite loop (#224)
cwaldren-ld Aug 29, 2023
eb1b3ed
feat: add DataSourceStatus() and plumb through IClient interface (#217)
cwaldren-ld Aug 30, 2023
b9c03e2
Merge branch 'main' into server-side
cwaldren-ld Aug 30, 2023
371ab00
refactor: move DataSourceStatus ErrorInfo C Bindings into common (#225)
cwaldren-ld Aug 30, 2023
61ddbe7
add Doxygen config and doc.md
cwaldren-ld Aug 30, 2023
aba2473
chore: add Server-side README (#226)
cwaldren-ld Aug 31, 2023
1538a76
fix: ensure flag updates go through data store updater (#228)
cwaldren-ld Aug 31, 2023
7ab8c1d
Merge branch 'main' into server-side
cwaldren-ld Aug 31, 2023
3669ff5
feat: server-side C bindings (#210)
cwaldren-ld Aug 31, 2023
4889549
feat: plumb server side initial backoff delay (#232)
cwaldren-ld Sep 1, 2023
d0ce48d
add story label to remaining test suppressions:
cwaldren-ld Sep 1, 2023
1db6db9
chore: resolve ValidChar function lint/compile warnings (#234)
cwaldren-ld Sep 5, 2023
5f04888
Merge branch 'main' into server-side
cwaldren-ld Sep 11, 2023
fe9e559
Merge branch 'main' into server-side
cwaldren-ld Sep 14, 2023
61a3bef
use async_connect() instead of run() in streaming data source
cwaldren-ld Sep 15, 2023
ede809d
Merge branch 'main' into server-side
cwaldren-ld Oct 18, 2023
a1751f3
build: fix LD_BUILD_SHARED_LIBS flag usage
cwaldren-ld Oct 18, 2023
32fc0ce
Merge branch 'cw/fix-shared-lib-variable' into server-side
cwaldren-ld Oct 18, 2023
f4c6542
use new cmake variables
cwaldren-ld Oct 18, 2023
6e428b4
one more missing usage
cwaldren-ld Oct 18, 2023
ed49fff
Merge branch 'cw/fix-shared-lib-variable' into server-side
cwaldren-ld Oct 18, 2023
29385ec
fix merge conflicts
cwaldren-ld Oct 18, 2023
f796566
fix hello-c-server compilation
cwaldren-ld Oct 18, 2023
5eeb40e
Merge branch 'main' into server-side
cwaldren-ld Oct 19, 2023
9c9ec0b
update server github workflow to better match client's
cwaldren-ld Oct 19, 2023
7760458
remove old-style user contract test suppressions
cwaldren-ld Oct 19, 2023
b0a6885
fix: enforce validated ContextKind usage in Segment data model (#263)
cwaldren-ld Oct 20, 2023
dc14199
formatting
cwaldren-ld Oct 19, 2023
880ab16
use WriteMinimal where possible for writing JSON
cwaldren-ld Oct 20, 2023
2c494ce
clang format
cwaldren-ld Oct 20, 2023
64ab87d
remove TODO about using initial reconnect delay (implemented)
cwaldren-ld Oct 20, 2023
ce9ae07
remove/resolve some TODOs
cwaldren-ld Oct 20, 2023
e217299
Merge branch 'main' into server-side
cwaldren-ld Oct 20, 2023
a6a7456
fix client-and-server-coexistence linking
cwaldren-ld Oct 20, 2023
9597b29
update client/server readmes and put CMake options in toplevel readme
cwaldren-ld Oct 20, 2023
943d07c
revert change to client data source status state
cwaldren-ld Oct 20, 2023
8179eba
remove unused evaluation detail API & remove implicit bool operator
cwaldren-ld Oct 20, 2023
6f1aba6
Merge branch 'main' into server-side
cwaldren-ld Oct 20, 2023
1da898d
Merge branch 'main' into server-side
cwaldren-ld Oct 20, 2023
df4ef40
add some story links for todos
cwaldren-ld Oct 23, 2023
d7453d3
remove object slicing in asio_event_processor
cwaldren-ld Oct 23, 2023
17a9d38
remove useless inheritance usage in server-side events
cwaldren-ld Oct 23, 2023
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
2 changes: 1 addition & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
CheckOptions:
- { key: readability-identifier-length.IgnoredParameterNames, value: 'i|j|k|c|os|it' }
- { key: readability-identifier-length.IgnoredVariableNames, value: 'ec|id' }
- { key: readability-identifier-length.IgnoredVariableNames, value: 'ec|id|it' }
- { key: readability-identifier-length.IgnoredLoopCounterNames, value: 'i|j|k|c|os|it' }
10 changes: 5 additions & 5 deletions .github/workflows/client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
paths-ignore:
- '**.md' #Do not need to run CI for markdown changes.
pull_request:
branches: [ main ]
Copy link
Contributor Author

@cwaldren-ld cwaldren-ld Oct 19, 2023

Choose a reason for hiding this comment

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

Can remove the server-side part once merge (and in other workflows.)

branches: [ main, server-side ]
paths-ignore:
- '**.md'

Expand All @@ -16,12 +16,12 @@ jobs:
env:
# Port the test service (implemented in this repo) should bind to.
TEST_SERVICE_PORT: 8123
TEST_SERVICE_BINARY: ./build/contract-tests/sdk-contract-tests/sdk-tests
TEST_SERVICE_BINARY: ./build/contract-tests/client-contract-tests/client-tests
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/ci
with:
cmake_target: sdk-tests
cmake_target: client-tests
run_tests: false
- name: 'Launch test service as background task'
run: $TEST_SERVICE_BINARY $TEST_SERVICE_PORT 2>&1 &
Expand All @@ -36,7 +36,7 @@ jobs:
- uses: ./.github/actions/ci
with:
cmake_target: launchdarkly-cpp-client
build-test-mac:
build-test-client-mac:
runs-on: macos-12
steps:
- run: |
Expand All @@ -50,7 +50,7 @@ jobs:
with:
cmake_target: launchdarkly-cpp-client
platform_version: 12
build-test-windows:
build-test-client-windows:
runs-on: windows-2022
steps:
- name: Upgrade OpenSSL
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ on:
paths-ignore:
- '**.md' #Do not need to run CI for markdown changes.
pull_request:
branches: [ main ]
branches: [ main, server-side ]
paths-ignore:
- '**.md'

jobs:
build-test:
build-test-common:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cpp-linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
branches: [ "main", server-side ]

jobs:
cpp-linter:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/internal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ on:
paths-ignore:
- '**.md' #Do not need to run CI for markdown changes.
pull_request:
branches: [ main ]
branches: [ main, server-side ]
paths-ignore:
- '**.md'

jobs:
build-test:
build-test-internal:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
Expand Down
79 changes: 79 additions & 0 deletions .github/workflows/server.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: libs/server-sdk

on:
push:
branches: [ main ]
paths-ignore:
- '**.md' #Do not need to run CI for markdown changes.
pull_request:
branches: [ main, server-side ]
paths-ignore:
- '**.md'

jobs:
contract-tests:
runs-on: ubuntu-22.04
env:
# Port the test service (implemented in this repo) should bind to.
TEST_SERVICE_PORT: 8123
TEST_SERVICE_BINARY: ./build/contract-tests/server-contract-tests/server-tests
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/ci
with:
cmake_target: server-tests
run_tests: false
- name: 'Launch test service as background task'
run: $TEST_SERVICE_BINARY $TEST_SERVICE_PORT 2>&1 &
- uses: ./.github/actions/contract-tests
with:
# Inform the test harness of test service's port.
test_service_port: ${{ env.TEST_SERVICE_PORT }}
extra_params: '-skip-from ./contract-tests/server-contract-tests/test-suppressions.txt'
build-test-server:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/ci
with:
cmake_target: launchdarkly-cpp-server
build-test-server-mac:
runs-on: macos-12
steps:
- run: |
echo "OPENSSL_ROOT_DIR=$(brew --prefix openssl@3)" >> "$GITHUB_ENV"
# For debugging
echo "OPENSSL_ROOT_DIR=$(brew --prefix openssl@3)"
- uses: actions/checkout@v3
- uses: ./.github/actions/ci
env:
OPENSSL_ROOT_DIR: ${{ env.OPENSSL_ROOT_DIR }}
with:
cmake_target: launchdarkly-cpp-server
platform_version: 12
build-test-server-windows:
runs-on: windows-2022
steps:
- name: Upgrade OpenSSL
shell: bash
run: |
choco upgrade openssl --no-progress
- name: Determine OpenSSL Installation Directory
shell: bash
run: |
if [ -d "C:\Program Files\OpenSSL-Win64" ]; then
echo "OPENSSL_ROOT_DIR=C:\Program Files\OpenSSL-Win64" >> "$GITHUB_ENV"
else
echo "OPENSSL_ROOT_DIR=C:\Program Files\OpenSSL" >> "$GITHUB_ENV"
fi
- uses: actions/checkout@v3
- uses: ilammy/msvc-dev-cmd@v1
- uses: ./.github/actions/ci
env:
OPENSSL_ROOT_DIR: ${{ env.OPENSSL_ROOT_DIR }}
BOOST_LIBRARY_DIR: 'C:\local\boost_1_81_0\lib64-msvc-14.3'
BOOST_LIBRARYDIR: 'C:\local\boost_1_81_0\lib64-msvc-14.3'
with:
cmake_target: launchdarkly-cpp-client
platform_version: 2022
toolset: msvc
2 changes: 1 addition & 1 deletion .github/workflows/sse.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
- '**.md'

jobs:
build-test:
build-test-sse:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ add_subdirectory(libs/server-sent-events)
# Built as static or shared depending on LD_BUILD_SHARED_LIBS variable.
# This target "links" in common, internal, and sse as object libraries.
add_subdirectory(libs/client-sdk)
add_subdirectory(libs/server-sdk)

if (LD_BUILD_CONTRACT_TESTS)
message(STATUS "LaunchDarkly: building contract tests")
Expand Down
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,40 @@ GoogleTest is used for testing.

For information on integrating an SDK package please refer to the SDK specific README.

## CMake Usage

Various CMake options are available to customize the client/server SDK builds.

| Option | Description | Default | Requires |
|---------------------------|----------------------------------------------------------------------------------------|--------------------|-------------------------------------------|
| `BUILD_TESTING` | Coarse-grained switch; turn off to disable all testing and only build the SDK targets. | On | N/A |
| `LD_BUILD_UNIT_TESTS` | Whether C++ unit tests are built. | On | `BUILD_TESTING; NOT LD_BUILD_SHARED_LIBS` |
| `LD_TESTING_SANITIZERS` | Whether sanitizers should be enabled. | On | `LD_BUILD_UNIT_TESTS` |
| `LD_BUILD_CONTRACT_TESTS` | Whether the contract test service (used in CI) is built. | Off | `BUILD_TESTING` |
| `LD_BUILD_EXAMPLES` | Whether example apps (hello world) are built. | On | N/A |
| `LD_BUILD_SHARED_LIBS` | Whether the SDKs are built as static or shared libraries. | Off (static lib) | N/A |
| `LD_DYNAMIC_LINK_OPENSSL` | Whether OpenSSL be dynamically linked. | Off (static link) | N/A |

**Note:** _if building the SDKs as shared libraries, then unit tests won't be able to link correctly since the SDK's C++
symbols aren't exposed. To run unit tests, build a static library._

Basic usage example:

```bash
mkdir -p build && cd build
cmake -G"Unix Makefiles" ..
```

Slightly more advanced example - build shared libraries, and don't build any of the testing components:

```bash
mkdir -p build && cd build
cmake -G"Unix Makefiles" -DLD_BUILD_SHARED_LIBS=On -DBUILD_TESTING=Off ..
```

The example uses `make`, but you might instead use [Ninja](https://ninja-build.org/),
MSVC, [etc.](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html)

## LaunchDarkly overview

[LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves trillions of feature flags
Expand Down Expand Up @@ -76,7 +110,8 @@ our [contributing guidelines](CONTRIBUTING.md) for instructions on how to contri
- Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get
access to more features than users in the ‘silver’ plan). Disable parts of your application to facilitate
maintenance, without taking everything offline.
- LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Read [our documentation](https://docs.launchdarkly.com/sdk) for a complete list.
- LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies.
Read [our documentation](https://docs.launchdarkly.com/sdk) for a complete list.
- Explore LaunchDarkly
- [launchdarkly.com](https://www.launchdarkly.com/ 'LaunchDarkly Main Website') for more information
- [docs.launchdarkly.com](https://docs.launchdarkly.com/ 'LaunchDarkly Documentation') for our documentation and SDK
Expand Down
145 changes: 145 additions & 0 deletions architecture/event_processor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Analytic Event Processor

The Event Processor is responsible for consuming, batching, and delivering events generated
by the server and client-side LaunchDarkly SDKs.

```mermaid
classDiagram
IEventProcessor <|-- NullEventProcessor
IEventProcessor <|-- AsioEventProcessor

AsioEventProcessor *-- LRUCache
AsioEventProcessor *-- Outbox
AsioEventProcessor *-- WorkerPool
AsioEventProcessor *-- Summarizer

RequestWorker *-- EventBatch
WorkerPool *-- "5" RequestWorker

TrackEvent -- TrackEventParams: (alias)
InputEvent *-- IdentifyEventParams
InputEvent *-- FeatureEventParams
InputEvent *-- TrackEventParams


OutputEvent *-- IndexEvent
OutputEvent *-- FeatureEvent
OutputEvent *-- DebugEvent
OutputEvent *-- IdentifyEvent
OutputEvent *-- TrackEvent

EventBatch --> Outbox: Pulls individual events from..
EventBatch --> Summarizer: Pulls summary events from..

IEventProcessor --> InputEvent
Outbox --> OutputEvent

Summarizer --> FeatureEventParams


class IEventProcessor {
<<interface>>
+SendAsync(InputEvent event) void
+FlushAsync() void
+ShutdownAsync() void
}

class NullEventProcessor {

}

class AsioEventProcessor {

}

class EventBatch {
+const Count() size_t
+const Request() network:: HttpRequest
+const Target() std:: string
}

class LRUCache {
+Notice(std:: string value) bool
+const Size() size_t
+Clear() void
}

class Outbox {
+PushDiscardingOverflow(std:: vector~OutputEvent~ events) bool
+Consume() std:: vector~OutputEvent~
+const Empty() bool
}

class RequestWorker {
+const Available() bool
+AsyncDeliver(EventBatch, delivery_callback)
}

class WorkerPool {
+Get(worker_callback) void
}

class Summarizer {
+Update(FeatureEventParams) void
+Finish()
+const StartTime() Time
+const EndTime() Time
}

%% note: the 'namespace' feature isn't supported on Github yet
%% namespace events {
class InputEvent {
+std:: variant
}


class OutputEvent {
+std:: variant
}

class FeatureEventParams {

}

class IdentifyEventParams {

}

class TrackEventParams {

}

class FeatureEvent {

}

class DebugEvent {

}

class IdentifyEvent {

}

class IndexEvent {

}

class TrackEvent {

}

%% }
```

### Notes

SDKs may be configured to disable events, so `NullEventProcessor` is made available. This component accepts
events generated
by the SDK and discards them.

If events are enabled, SDKs use the `AsioEventProcessor` implementation, which is an asynchronous processor
utilizing `boost::asio`.

Most event definitions are shared between the server and client-side SDKs. Unique to the server-side SDK
is `IndexEvent`.
Loading
Loading