feat(go): add Go package with wazero WASM runtime, instance pool, and optimized parsing#71
Merged
Conversation
…uation
Reduce targeting flag evaluation latency for large contexts by avoiding
unnecessary data transfer across the WASM boundary.
Rust side:
- Walk compiled targeting trees to extract referenced context keys
(e.g. {"var": "email"} -> "email") during update_state()
- Return per-flag requiredContextKeys and flagIndices in UpdateStateResponse
- Add evaluate_by_index(u32, ctx_ptr, ctx_len) WASM export for O(1) flag
lookup by numeric index instead of string key HashMap lookup
- Add evaluate_flag_pre_enriched() that skips context enrichment when
$flagd is already present (host-side enrichment)
Java side:
- Cache requiredContextKeys and flagIndices from updateState() response
- EvaluationContextSerializer.serializeFiltered() serializes only the
context keys a targeting rule references, plus $flagd enrichment
- evaluateFlag(EvaluationContext) uses filtered serialization + index-based
eval when available, falls back to full serialization gracefully
- evaluateByIndex() calls the new WASM export with O(1) Vec lookup
JMH results (1000+ attribute LayeredEvaluationContext):
- Targeting flags: ~12.8 µs (down from ~167 µs) — 13x improvement
- vs old json-logic-java: 32-34x faster (409 µs -> 12.8 µs)
- Static/disabled flags: ~0.02 µs (pre-evaluated cache, unchanged)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Go package for evaluating feature flags using the flagd-evaluator WASM module. Uses wazero for zero-CGO WebAssembly execution. Implements all 3 host-side optimizations from day 1: - Pre-evaluation cache for static/disabled flags (~24ns, 0 allocs) - Context key filtering (only serialize keys referenced by targeting rules) - Index-based WASM evaluation (O(1) flag lookup via evaluate_by_index) Includes 14 integration tests mirroring Java's FlagEvaluatorTest, full BENCHMARKS.md matrix (E1-E11, O1-O6, S1-S5, C1-C6), and comparison benchmarks against diegoholiveira/jsonlogic/v3 showing 40x speedup on large contexts due to context filtering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…benchmarks Replace single-mutex architecture with a pool of WASM instances for parallel targeting evaluation. Pre-evaluated (static/disabled) flags are now served lock-free via atomic cache pointers. Key changes: - Instance pool: N WASM instances (default runtime.NumCPU()) evaluate targeting flags in parallel instead of serializing on one mutex - Generation guard: atomic generation counter prevents stale flag index usage when UpdateState races with evaluateFlag - Hand-rolled JSON parser: avoids json.Unmarshal reflection overhead for EvaluationResult (5-7x faster for common cases, 4.6x for metadata) - Throughput benchmarks (T1-T9): 1000 evals across 1/4/16 goroutines to expose scaling behavior - Comparison throughput benchmarks: WASM pool vs native jsonlogic at varying concurrency levels Targeting throughput at 16 goroutines: 5.7ms → 1.7ms (3.4x improvement) Mixed workload at 16 goroutines: 2.0ms → 0.74ms (2.7x improvement) Pre-evaluated flags: now fully lock-free (no mutex) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WASM tests share a thread-local singleton evaluator, so they must run sequentially. Gherkin tests use cucumber which doesn't support --test-threads, so they run separately without the flag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Go package has 13+ tests covering evaluation, parsing, concurrency, and scale scenarios. Add a CI job that runs them using the embedded WASM binary already committed in the go/ directory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8 tasks
Instead of relying on the committed WASM binary, build it from Rust source in CI. This ensures Go tests always run against the correct WASM matching the current Rust code. Refs: #83 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
go/) for evaluating feature flags using the flagd-evaluator WASM moduleevaluate_by_indexfor O(1) flag lookup, avoiding string serializationruntime.NumCPU()) for parallel targeting evaluationjson.Unmarshalreflection overhead (5-7x faster)UpdateStateand concurrent evaluationsArchitecture
Per-Evaluation Latency (single goroutine)
Throughput Scaling (1000 evals across N goroutines)
Targeting, small context:
Targeting, large context (1000+ attrs):
Mixed workload (static + targeting + disabled):
JSON Result Parsing (hand-rolled vs
json.Unmarshal)json.UnmarshalFiles
wasm.go//go:embed, memory helpershost.gotypes.goEvaluationResult,UpdateStateResult, options (WithPoolSize,WithPermissiveValidation)evaluator.goUpdateStatewith parallel instance sync, generation stampingevaluate.goparse.goEvaluationResult(nojson.Unmarshalon hot path)evaluator_test.goTestGenerationGuardrace testbenchmark_test.gocomparison_test.godiegoholiveira/jsonlogic/v3fast_parse_test.goTest plan
go test -v -race)-racedetector (5 runs)go test -bench=. -benchmem)go test -tags comparison -bench=.)go build ./...clean🤖 Generated with Claude Code