Skip to content

feat: Add async feature flag evaluation#720

Draft
marandaneto wants to merge 5 commits into
async-sdk-01-capturefrom
async-sdk-02-feature-flags
Draft

feat: Add async feature flag evaluation#720
marandaneto wants to merge 5 commits into
async-sdk-01-capturefrom
async-sdk-02-feature-flags

Conversation

@marandaneto

@marandaneto marandaneto commented Jul 1, 2026

Copy link
Copy Markdown
Member

💡 Motivation and Context

Continues the async SDK stack for #103 by adding non-blocking feature flag and remote config APIs on top of AsyncPosthog.

This PR is stacked on #719. It replaces blocking /flags, flag definition polling, and remote config calls in the async client with awaitable HTTP helpers, while keeping FeatureFlagEvaluations.is_enabled() / .get_flag() synchronous for ergonomic branching. $feature_flag_called events are scheduled into the async capture queue and drained by await flush() / await shutdown().

Review feedback was addressed by making feature-flag-called scheduling gracefully no-op with a warning when accessed without a running event loop, asserting the async poller task is started, and adding parameterized remote config coverage.

💚 How did you test it?

  • uv run ruff check posthog/async_client.py posthog/test/test_async_client.py posthog/test/test_async_feature_flags.py
  • uv run --extra test pytest posthog/test/test_async_request.py posthog/test/test_async_client.py posthog/test/test_async_feature_flags.py --verbose --timeout=30
  • uv run --extra test pytest posthog/test/test_evaluate_flags.py posthog/test/test_feature_flags.py --verbose --timeout=30
  • uv run python -W error -c "import posthog; from posthog import AsyncPosthog"
  • uv run --extra dev python .github/scripts/check_public_api.py

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran sampo add to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Implemented with pi. The main design choice was to keep flag snapshots synchronous to read after await evaluate_flags(...), and to schedule their $feature_flag_called side effects into the async client instead of making every flag accessor awaitable.

@marandaneto marandaneto self-assigned this Jul 1, 2026
@marandaneto marandaneto mentioned this pull request Jul 1, 2026
5 tasks
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

posthog-python Compliance Report

Date: 2026-07-02 14:14:53 UTC
Duration: 177175ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 516ms
Format Validation.Event Has Uuid 1508ms
Format Validation.Event Has Lib Properties 1507ms
Format Validation.Distinct Id Is String 1506ms
Format Validation.Token Is Present 1506ms
Format Validation.Custom Properties Preserved 1507ms
Format Validation.Event Has Timestamp 1507ms
Retry Behavior.Retries On 503 9515ms
Retry Behavior.Does Not Retry On 400 3507ms
Retry Behavior.Does Not Retry On 401 3507ms
Retry Behavior.Respects Retry After Header 9514ms
Retry Behavior.Implements Backoff 23516ms
Retry Behavior.Retries On 500 7511ms
Retry Behavior.Retries On 502 7512ms
Retry Behavior.Retries On 504 7515ms
Retry Behavior.Max Retries Respected 23528ms
Deduplication.Generates Unique Uuids 1497ms
Deduplication.Preserves Uuid On Retry 7515ms
Deduplication.Preserves Uuid And Timestamp On Retry 14511ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 7512ms
Deduplication.No Duplicate Events In Batch 1507ms
Deduplication.Different Events Have Different Uuids 1507ms
Compression.Sends Gzip When Enabled 1506ms
Batch Format.Uses Proper Batch Structure 1505ms
Batch Format.Flush With No Events Sends Nothing 1005ms
Batch Format.Multiple Events Batched Together 1505ms
Error Handling.Does Not Retry On 403 3509ms
Error Handling.Does Not Retry On 413 3508ms
Error Handling.Retries On 408 7508ms

Feature_Flags Tests

17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 1007ms
Request Payload.Flags Request Uses V2 Query Param 1006ms
Request Payload.Flags Request Hits Flags Path Not Decide 1007ms
Request Payload.Flags Request Omits Authorization Header 1006ms
Request Payload.Token In Flags Body Matches Init 1006ms
Request Payload.Groups Round Trip 1006ms
Request Payload.Groups Default To Empty Object 1006ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False 1006ms
Request Payload.Disable Geoip Omitted Defaults To False 1006ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key 1005ms
Request Lifecycle.No Flags Request On Init Alone 503ms
Request Lifecycle.No Flags Request On Normal Capture 1507ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests 1011ms
Request Lifecycle.Mock Response Value Is Returned To Caller 1001ms
Retry Behavior.Retries Flags On 502 1004ms
Retry Behavior.Retries Flags On 504 1007ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event 1509ms

@marandaneto marandaneto force-pushed the async-sdk-02-feature-flags branch from 5376ad0 to 218c362 Compare July 1, 2026 13:07
@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "Add async feature flag evaluation" | Re-trigger Greptile

Comment thread posthog/async_client.py
Comment thread posthog/test/test_async_feature_flags.py
Comment thread posthog/test/test_async_feature_flags.py
@marandaneto marandaneto force-pushed the async-sdk-02-feature-flags branch 5 times, most recently from 83794b2 to ce3aa46 Compare July 2, 2026 11:15
@marandaneto marandaneto force-pushed the async-sdk-01-capture branch from f3fed37 to 8816f29 Compare July 2, 2026 11:18
@marandaneto marandaneto force-pushed the async-sdk-02-feature-flags branch from ce3aa46 to d1e9ab5 Compare July 2, 2026 11:23
@marandaneto marandaneto force-pushed the async-sdk-01-capture branch from 8816f29 to cfe5d0f Compare July 2, 2026 11:25
@marandaneto marandaneto force-pushed the async-sdk-02-feature-flags branch from d1e9ab5 to a365483 Compare July 2, 2026 11:26
@marandaneto marandaneto force-pushed the async-sdk-01-capture branch from cfe5d0f to 3b1a554 Compare July 2, 2026 11:28
@marandaneto marandaneto force-pushed the async-sdk-02-feature-flags branch from a365483 to 84f6ba5 Compare July 2, 2026 11:29
@marandaneto marandaneto force-pushed the async-sdk-02-feature-flags branch from 84f6ba5 to 7f102b9 Compare July 2, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant