This review covers the production risks requested for the Python Server SDK: unit behavior, WebSocket synchronization, event processing, evaluation, logging/error isolation, thread safety, shutdown, memory retention, redundant code, and live FeatBit service interoperability.
The review found and fixed the following concrete issues:
RepeatableTaskstored anEventinThread._stop, which breaks Python's ownThread.join()cleanup path. It now uses a separate stop event and joins deterministically.- WebSocket reconnect backoff used an uninterruptible sleep. Client shutdown now interrupts the wait, closes the socket defensively, stops the ping task, and joins the streaming thread.
- The notice broadcaster mutated its listener registry concurrently. Listener operations now use a lock and dispatch from an immutable snapshot; a queue sentinel makes shutdown immediate and repeatable.
- The event processor did not retain or join its dispatcher. It now owns the dispatcher lifecycle, joins the periodic flush task, and always completes a synchronous message even if message handling fails.
FBClient.stop()could expose an extension exception and skip all later cleanup. Shutdown is now idempotent, producer-first, and isolates each component failure.- Custom event processor errors could escape from
identify,track_*, orflush. Event delivery is now best-effort and cannot fail the application request. - Invalid offline bootstrap JSON and unsupported runtime fallback objects could
raise from evaluation-related calls. They now return
Falseor the supplied fallback, with a diagnostic log message. Configand the HTTP helper used mutable default objects. Each client now gets independent HTTP/WebSocket options and headers.- A duplicate
FBUser.from_dict()call intrack_metricwas removed.
Constructor/configuration validation still raises for invalid required configuration. This is intentional fail-fast behavior before an SDK client is usable; runtime evaluation, event, status, and shutdown paths are isolated.
Run from the repository root:
python -m pytest
python -m flake8 .
python scripts/resource_audit.py --evaluations 80000 --workers 8
python -m buildResult on Python 3.12.13 (2026-08-07):
- 83 unit/integration tests passed.
- Flake8 passed.
- 80,000 evaluations across 8 workers completed with 0 concurrent errors.
- Throughput was 12,490 evaluations/second on the final audit run.
- No FeatBit SDK worker threads remained after shutdown.
- 24,417 traced bytes remained after garbage collection, below the 2 MiB regression threshold.
- A clean wheel built from the source distribution contained 27 files, no
tests/package, and no stalefeatbit_openfeature/package.
The tests specifically cover concurrent evaluation, status-listener ordering, listener registration/removal under contention, event-processor failure isolation, repeated client lifecycle, periodic task joining, and interrupting a blocked WebSocket lifecycle.
Use a real environment Server Key without storing it in the repository:
export FEATBIT_ENV_SECRET='<server-key>'
export FEATBIT_FLAG_KEY='python-app-release'
python scripts/live_integration_check.pyOptional variables are FEATBIT_STREAMING_URL, FEATBIT_EVENT_URL, and
FEATBIT_START_WAIT_SECONDS. The script verifies:
- authenticated WebSocket connection and initial data synchronization;
- SDK status reaches
OK; - remote flag evaluation returns value, reason, and variation ID;
- feature-flag, identify, and custom metric events enter the delivery path;
- explicit flush and final synchronous drain complete;
- status changes to
OFFand no SDK threads remain after close.
The secret is read only from the process environment and is never printed or written to disk.
A recorded FeatBit Cloud run on 2026-07-24 reached the WebSocket connected
state, processed the initial data-sync payload, evaluated the remote
python-app-release flag, exercised the gray-release application under
concurrent HTTP traffic, and later demonstrated automatic reconnection after a
remote-host disconnect. The checked-in script turns that one-off validation
into a repeatable, secret-safe release check.
An additional run on 2026-08-07 used the official FeatBit Docker Compose stack.
It observed a remotely pushed rollout update in 0.5 seconds, completed 4,000
concurrent evaluations without errors, verified the default event-delivery
path, handled a status listener that re-entered client.stop() without a
deadlock, reached OFF, and left no SDK worker threads behind.
- The SDK is designed as a long-lived singleton, not one client per request.
- Event delivery is intentionally best-effort so analytics failure cannot affect application availability.
- A custom
DataStorage,EventProcessor, orUpdateProcessorremains responsible for its own internal correctness; the client isolates its runtime and shutdown exceptions. - Memory thresholds are regression guards, not universal capacity limits; production sizing should use the application's real flag and segment data.