Skip to content

Commit

Permalink
chore: cleanup SSE refrences on architecture page (#794)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathannorris authored Jan 21, 2025
1 parent 0f11860 commit 49b7148
Showing 1 changed file with 44 additions and 46 deletions.
90 changes: 44 additions & 46 deletions docs/essentials/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,73 @@ sidebar_position: 3
---

When building DevCycle, we decided on a couple of core design goals from our experience of building global services and SDKs:

- SDKs should be easy to understand and have consistent functionality across platforms.
- Feature Flags should evaluate quickly and be served from as close to the end user as possible.
- Business-critical code should be shared across platforms to ensure consistency and reduce bugs.
- A cross-platform end-to-end test-harness is required to ensure SDKs are working as expected.
- A cross-platform end-to-end test-harness is required to ensure SDKs are working as expected.
- SDKs should limit the number of start options that change the core behaviour of the SDK.

With these design goals in mind, we have developed a set of Client / Mobile / Server SDKs that deliver
With these design goals in mind, we have developed a set of Client / Mobile / Server SDKs that deliver
fast global response times and local evaluation of feature flag values. The following explanations of our
various SDK architectures have generally been fully implemented, outside of some instances where we still
need to implement Server-Sent Event (SSE) connections fully.
various SDK architectures have generally been fully implemented.

## How our APIs build Configuration data

![architexture-api-diagram.svg](/architexture-api-diagram.svg)

1. Features created in the Dashboard interact directly with our public **[Management API](/management-api/)**,
to create and manage various models like Audiences / Features / Variables / Variations / etc.
1. Features created in the Dashboard interact directly with our public **[Management API](/management-api/)**,
to create and manage various models like Audiences / Features / Variables / Variations / etc.

2. Changes made by the **Management API** are delivered via a queue to the **Config Service**.
2. Changes made by the **Management API** are delivered via a queue to the **Config Service**.

3. The **Config Service** bundles all changes into a JSON configuration for each Project, Environment,
and SDK type combination.
3. The **Config Service** bundles all changes into a JSON configuration for each Project, Environment,
and SDK type combination.

4. The configuration data is then uploaded to **Cloudflare's CDN**.

5. Changes to the configuration data trigger **Cloudflare's CDN** cache invalidation,
which can serve new data in approximately ~1 second globally.
5. Changes to the configuration data trigger **Cloudflare's CDN** cache invalidation,
which can serve new data in approximately ~1 second globally.

6. Finally, an update notification is pushed to all connected SDKs via a server-sent event (SSE) connection
that informs them that new configuration data updates are available.
that informs them that new configuration data updates are available.

## Shared Bucketing and Segmentation Library

The shared bucketing and segmentation library is the core of our SDKs and API logic. It combines configuration data
containing Feature / Variable / Variation / Audience / Targeting Rule definitions with user data to bucket users into
The shared bucketing and segmentation library is the core of our SDKs and API logic. It combines configuration data
containing Feature / Variable / Variation / Audience / Targeting Rule definitions with user data to bucket users into
features and variations and determines variable values.

Most of our APIs and SDKs use a shared WebAssembly (WASM)
[bucketing and segmentation library](https://github.com/DevCycleHQ/js-sdks/tree/main/lib/shared/bucketing-assembly-script).
Most of our APIs and SDKs use a shared WebAssembly (WASM)
[bucketing and segmentation library](https://github.com/DevCycleHQ/js-sdks/tree/main/lib/shared/bucketing-assembly-script).
The portability of the WASM codebase allows us to achieve the following goals:

- **Fast**: WASM is compiled in a load-time-efficient binary format, quickly loaded, and executed at near-native speeds.

- **Portable**: WASM is a portable binary format that runs on various supporting platforms.
We use the recommended WASMTime runtimes supported by the Bytecode Alliance across our SDKs.
It enables us to share the same core feature flag decisioning logic across all our SDKs and edge-based APIs.
- **Portable**: WASM is a portable binary format that runs on various supporting platforms.
We use the recommended WASMTime runtimes supported by the Bytecode Alliance across our SDKs.
It enables us to share the same core feature flag decisioning logic across all our SDKs and edge-based APIs.

- **Well Tested**: By relying on one core library making decisions across our SDKs and APIs,
we can more easily ensure it is well-tested and reliable. In addition to thorough unit testing,
we have a cross-platform end-to-end SDK test-harness to ensure platform consistency.
- **Well Tested**: By relying on one core library making decisions across our SDKs and APIs,
we can more easily ensure it is well-tested and reliable. In addition to thorough unit testing,
we have a cross-platform end-to-end SDK test-harness to ensure platform consistency.

- **Secure**: WASM runs in a [memory-safe sandboxed execution environment](https://webassembly.org/docs/security/)
that has proven its security credentials across web browsers.
that has proven its security credentials across web browsers.

However, WASM is not a silver bullet, and for certain very high performance/concurrent threading use cases,
However, WASM is not a silver bullet, and for certain very high performance/concurrent threading use cases,
we have built a native implementation, for example, in our [GO SDK](https://github.com/DevCycleHQ/go-server-sdk).

## Local Bucketing Server SDK Architecture

![Architecture Docs Diagrams - Local Server SDK.svg](/architecture-docs-diagrams-local-server-sdk.svg)

**Note: Server-sent event support for Server SDKs is currently under development.**

1. On initialization, the Server SDK retrieves the configuration data from the CDN and stores it locally.

2. On each `variableValue()` / `variable()` call, the bucketing and segmentation library combines user data, device data,
and configuration data locally to bucket users into features and variations to determine variable values.
2. On each `variableValue()` / `variable()` call, the bucketing and segmentation library combines user data, device data,
and configuration data locally to bucket users into features and variations to determine variable values.

3. Configuration updates are received via polling against the CDN or through a real-time server-sent event (SSE) connection.
3. Configuration updates are received through a real-time server-sent event (SSE) connection or as a backup via polling against the CDN.

4. Event data is aggregated within the SDK and sent to the Events API on an interval.

Expand All @@ -84,39 +82,39 @@ For most use cases, local bucketing SDKs provide superior performance and reliab
However, the cloud-bucketing SDKs can make integration easier for specific use cases where access to
[EdgeDB](/platform/feature-flags/targeting/edgedb) to integrate user data between client-side and backend applications is needed.

1. On each `variableValue()` / `variable()` call, the Cloud Bucketing Server SDKs fetch data from the
[Bucketing API](/bucketing-api/) served by Cloudflare Workers at the edge.
1. On each `variableValue()` / `variable()` call, the Cloud Bucketing Server SDKs fetch data from the
[Bucketing API](/bucketing-api/) served by Cloudflare Workers at the edge.

2. The Bucketing API calls the shared bucketing and segmentation library to combine user, device,
and configuration data to bucket the user into features and variations to determine variable values.
2. The Bucketing API calls the shared bucketing and segmentation library to combine user, device,
and configuration data to bucket the user into features and variations to determine variable values.

3. Event data is aggregated within the SDK and sent to the Events API on an interval.

## Client + Mobile SDK Architecture

![Architecture Docs Diagrams - Client Mobile SDK.svg](/architecture-docs-diagrams-client-mobile-sdk.svg)

1. On initialization, Mobile and Client SDKs call the Client SDK API served by Cloudflare Workers at the edge.
The SDK will fall back to the previously cached configuration data or default values on a failed connection.
1. On initialization, Mobile and Client SDKs call the Client SDK API served by Cloudflare Workers at the edge.
The SDK will fall back to the previously cached configuration data or default values on a failed connection.

2. The Client SDK API calls the shared bucketing and segmentation library to combine user, device,
and configuration data to bucket the user into features and variations to determine variable values.
This data is returned to the SDKs to be cached locally and used each time `variableValue()` / `variable()` is called.
2. The Client SDK API calls the shared bucketing and segmentation library to combine user, device,
and configuration data to bucket the user into features and variations to determine variable values.
This data is returned to the SDKs to be cached locally and used each time `variableValue()` / `variable()` is called.

3. When user data is updated using the `identifyUser()` or `resetUser()` methods, the SDKs will
request a new configuration from the Client SDK API.
3. When user data is updated using the `identifyUser()` or `resetUser()` methods, the SDKs will
request a new configuration from the Client SDK API.

4. The Client SDKs make SSE connections to receive real-time updates, which trigger a request for an
updated configuration from the Client SDK API.
4. The Client SDKs make SSE connections to receive real-time updates, which trigger a request for an
updated configuration from the Client SDK API.

5. Event data is sent at intervals to our Events API.

## SDK Test Harness

Our [SDK Test Harness](https://github.com/DevCycleHQ/test-harness) aims to define a set of standardized end-to-end tests
that run against multiple SDKs written in different languages. The tests are defined using Jest, and are run using
Our [SDK Test Harness](https://github.com/DevCycleHQ/test-harness) aims to define a set of standardized end-to-end tests
that run against multiple SDKs written in different languages. The tests are defined using Jest, and are run using
a set of HTTP requests made to a series of locally run proxy servers for each SDK language.

These proxy servers then take the commands from the requests made from the tests to set up the SDKs in different ways,
execute all the core SDK methods, and measure their responses. They ensure that each SDK behaves the same way,
These proxy servers then take the commands from the requests made from the tests to set up the SDKs in different ways,
execute all the core SDK methods, and measure their responses. They ensure that each SDK behaves the same way,
returns the same results, or throws the same errors for each test.

0 comments on commit 49b7148

Please sign in to comment.