AA.View source

PLATFORM ENGINEERING · .NET

Feature Flags
Service

A self-hosted feature flag service and .NET SDK. I built it to evaluate flags quickly, cache definitions and send updates to connected clients.

.NET 10C#PostgreSQLRedisFusionCacheSignalR

INDEPENDENT PROOF OF CONCEPT Runs with self-hosted infrastructure; no public live API.

LOCAL k6 RUN · WARM FLAG CACHE49,850average requests per second
3.91 msp99 response time

Release build · API host-pinned to two cores · 30s warm-up + 2m measurement

~6Mrequests over the measured run
0failed requests in that run
79automated tests passed
dotnet test · all projects
50kpeak requests per second in the local run

01 / WHY I BUILT IT

Why I built
the service.

Feature flag checks sit on request paths. I wanted to build a self-hosted .NET service that keeps flag definitions close to the API, evaluates targeting rules for each request and sends changes to connected clients.

It gave me a way to work through caching and invalidation, deterministic rollouts, a typed client SDK, automated tests and load testing in one project.

02 / ARCHITECTURE

How the pieces
fit together.

The API and application code hold the service logic; infrastructure handles PostgreSQL, Redis and caching.

Conceptual feature flags service architectureClient SDK calls the .NET API, which evaluates flags using cached definitions backed by PostgreSQL. Redis provides distributed cache storage, invalidation backplane and SignalR scale-out. Prometheus and Grafana observe the API; k6 drives local load tests.Client app.NET SDK · ETag cache*.NET 10 APIMinimal API · ApplicationFusionCacheIn-memory L1RedisDistributed L2PostgreSQLPersistent source of truthSignalRFlagChanged updatesPrometheusScrapes /metricsk6Local load generatorGrafana

Conceptual view of implemented components; it does not describe a live production deployment. Redis also carries the FusionCache invalidation backplane and SignalR scale-out. *SDK caching is optional.

Request / data flowBenchmark / telemetry

03 / UNDER THE HOOD

A few decisions
behind the code.

01

Compute evaluations; cache definitions

The active v1.1 path reads a cached flag definition, then computes the user result on every request. Percentage rollouts use deterministic XxHash32 bucketing; span-based list parsing avoids splitting strings into temporary arrays. ADR 0002 records the move away from per-user result caching.

EvaluationService.cs·ADR 0002
02

Cache the thing that changes less

CachedFeatureFlagRepository decorates the repository. FusionCache uses process memory as L1 and Redis as L2, with fail-safe and eager refresh options. Writes update cached values and remove related entries; its Redis backplane distributes invalidations between instances. PostgreSQL remains the persisted source of truth.

Cached repository·Cache registration
03

A typed client with opt-in ergonomics

The .NET SDK provides typed access to evaluation and management endpoints. Conditional ETag caching and the DI package retry handler are available for callers to configure; they are not implicit behavior of every client. The included Blazor sample demonstrates flag evaluation and SignalR updates locally.

Client implementation·Optional retry handler
04

Measure the API and its dependencies

The API exposes Prometheus metrics; dashboards in Grafana include request and cache signals. k6 drives the documented local load test. Tests cover service and client behavior, while the benchmark is evidence for one machine and one workload—not a general capacity promise.

Observability setup·Evaluation endpoint

04 / PERFORMANCE

Benchmarked on
my machine.

The v1.1 run was recorded on 20 February 2026.

AVERAGE THROUGHPUT49,850 req/s
p95 LATENCY2.60 ms
p99 LATENCY3.91 ms
FAILED REQUESTS0 of ~6M

Windows 11 · Ryzen 9 9950X3D · 64 GB RAM. API Release process pinned to two cores; PostgreSQL, Redis, Prometheus and Grafana in Docker; k6 ran on the host over localhost. The flag-definition cache was warm: 30-second warm-up, then two minutes of measurement (75 preallocated / 150 max virtual users). This is a single-machine local result, and does not establish behavior under internet latency, multi-node deployment or other workloads.

Full methodology, measurements and earlier-run caveats

05 / SCOPE & NEXT STEPS

A useful PoC,
with room to grow.

The repository explicitly describes this as a proof of concept, not a production-ready service. Its README lists rate limiting as unimplemented. The published 50k screenshots predate the v1.1 computed-evaluation run, and the distributed benchmark documentation describes a test procedure rather than published distributed results.

Infrastructure documentation calls out dedicated cluster testing as future work; the local benchmark notes that dedicated infrastructure would give more representative results. I would extend validation across nodes and failure scenarios before making production capacity claims.

Core service and SDK paths have automated tests, but the current project should still be treated as an engineering demonstration. The metrics here do not imply external users, availability commitments or a hosted service.

06 / GO DEEPER

Read the source
and the decisions.