diff --git a/README.md b/README.md index f77d9f3..fbf3757 100644 --- a/README.md +++ b/README.md @@ -203,11 +203,12 @@ This client uses go routines to report several events and doesn't drain the chan ### Feature Resolver -`FeatureResolver` is a `FeatureOption` used in `IsEnabled` via the `WithResolver`. +`FeatureResolver` is a `FeatureOption` used in `IsEnabled` via the `WithResolver`. The `FeatureResolver` can be used to provide a feature instance in a different way than the client would normally retrieve it. This alternative resolver can be useful if you already have the feature instance and don't want to incur the cost to retrieve it from the repository. An example of its usage is below: + ```go ctx := context.Context{ UserId: "123", @@ -238,7 +239,7 @@ resolver := func(featureName string) *api.Feature { } } -// This would return true because the matched strategy is default and the feature is Enabled +// This would return true because the matched strategy is default and the feature is Enabled unleash.IsEnabled("someToggle", unleash.WithContext(ctx), unleash.WithResolver(resolver)) ``` @@ -286,3 +287,29 @@ Run code-style checks:(currently failing) Run race-tests: make test-race + +## Benchmarking + +You can benchmark feature toggle evaluation by running: + +``` +go test -run=^$ -bench=BenchmarkFeatureToggleEvaluation -benchtime=10s +``` + +Here's an example of how the output could look like: + +``` +goos: darwin +goarch: arm64 +pkg: github.com/Unleash/unleash-client-go/v3 +BenchmarkFeatureToggleEvaluation-8 Final Estimated Operations Per Day: 101.131 billion (1.011315e+11) +13635154 854.3 ns/op +PASS +ok github.com/Unleash/unleash-client-go/v3 13.388s +``` + +In this example the benchmark was run on a MacBook Pro (M1 Pro, 2021) with 16GB RAM. + +We can see a result of **854.3 ns/op**, which means around **101.131 billion** feature toggle evaluations per day. + +**Note**: The benchmark is run with a single CPU core, no parallelism. diff --git a/benchmark_test.go b/benchmark_test.go new file mode 100644 index 0000000..88e6c74 --- /dev/null +++ b/benchmark_test.go @@ -0,0 +1,50 @@ +package unleash_test + +import ( + "fmt" + "net/http" + "testing" + "time" + + "github.com/Unleash/unleash-client-go/v3" +) + +type NoOpListener struct{} + +func (l *NoOpListener) OnReady() {} +func (l *NoOpListener) OnError(err error) {} +func (l *NoOpListener) OnWarning(warning error) {} +func (l *NoOpListener) OnCount(name string, enabled bool) {} +func (l *NoOpListener) OnSent(payload unleash.MetricsData) {} +func (l *NoOpListener) OnRegistered(payload unleash.ClientData) {} + +func BenchmarkFeatureToggleEvaluation(b *testing.B) { + unleash.Initialize( + unleash.WithListener(&NoOpListener{}), + unleash.WithAppName("go-benchmark"), + unleash.WithUrl("https://app.unleash-hosted.com/demo/api/"), + unleash.WithCustomHeaders(http.Header{"Authorization": {"Go-Benchmark:development.be6b5d318c8e77469efb58590022bb6416100261accf95a15046c04d"}}), + ) + + b.ResetTimer() + startTime := time.Now() + + for i := 0; i < b.N; i++ { + _ = unleash.IsEnabled("go-benchmark") + } + + endTime := time.Now() + b.StopTimer() + + // Calculate ns/op (nanoseconds per operation) + nsPerOp := float64(endTime.Sub(startTime).Nanoseconds()) / float64(b.N) + + // Calculate operations per day + opsPerSec := 1e9 / nsPerOp + opsPerDay := opsPerSec * 60 * 60 * 24 + + if b.N > 1000000 { // Only print if the number of iterations is large enough for a stable result + opsPerDayBillions := opsPerDay / 1e9 // Convert to billions + fmt.Printf("Final Estimated Operations Per Day: %.3f billion (%e)\n", opsPerDayBillions, opsPerDay) + } +}