Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(flags): send feature_flag_called events with correct payload data in the event that we need to fetch the payloads from the server #315

Merged
merged 10 commits into from
Nov 26, 2024

Conversation

dmarticus
Copy link
Contributor

@dmarticus dmarticus commented Nov 21, 2024

Follow on to this discussion and this slack thread, it looks like the bug with the Python SDK (where we send empty responses in our feature_flag_called events when we call get_feature_flag_payload) is also present in the Node SDK.

This change makes it so that we ensure that we have a relevant response + payload to send on the event body whenever we fall back to remotely evaluating the feature flag payload.

@dmarticus dmarticus marked this pull request as draft November 21, 2024 22:19
Copy link

github-actions bot commented Nov 21, 2024

Size Change: +500 B (+0.46%)

Total Size: 108 kB

Filename Size Change
posthog-node/lib/index.cjs.js 21 kB +250 B (+1.21%)
posthog-node/lib/index.esm.js 20.9 kB +250 B (+1.21%)
ℹ️ View Unchanged
Filename Size
posthog-react-native/lib/posthog-core/src/eventemitter.js 1.08 kB
posthog-react-native/lib/posthog-core/src/index.js 9.9 kB
posthog-react-native/lib/posthog-core/src/lz-string.js 1.42 kB
posthog-react-native/lib/posthog-core/src/types.js 365 B
posthog-react-native/lib/posthog-core/src/utils.js 822 B
posthog-react-native/lib/posthog-core/src/vendor/uuidv7.js 2.04 kB
posthog-react-native/lib/posthog-react-native/index.js 485 B
posthog-react-native/lib/posthog-react-native/src/autocapture.js 1.8 kB
posthog-react-native/lib/posthog-react-native/src/frameworks/wix-navigation.js 651 B
posthog-react-native/lib/posthog-react-native/src/hooks/useFeatureFlag.js 437 B
posthog-react-native/lib/posthog-react-native/src/hooks/useFeatureFlags.js 362 B
posthog-react-native/lib/posthog-react-native/src/hooks/useLifecycleTracker.js 416 B
posthog-react-native/lib/posthog-react-native/src/hooks/useNavigationTracker.js 628 B
posthog-react-native/lib/posthog-react-native/src/hooks/usePostHog.js 249 B
posthog-react-native/lib/posthog-react-native/src/legacy.js 810 B
posthog-react-native/lib/posthog-react-native/src/native-deps.js 1.17 kB
posthog-react-native/lib/posthog-react-native/src/optional/OptionalAsyncStorage.js 183 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoApplication.js 215 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoDevice.js 211 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoFileSystem.js 224 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoLocalization.js 216 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeDeviceInfo.js 220 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeNavigation.js 218 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeNavigationWix.js 222 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalSessionReplay.js 231 B
posthog-react-native/lib/posthog-react-native/src/posthog-rn.js 4.16 kB
posthog-react-native/lib/posthog-react-native/src/PostHogContext.js 210 B
posthog-react-native/lib/posthog-react-native/src/PostHogProvider.js 1.57 kB
posthog-react-native/lib/posthog-react-native/src/storage.js 1.09 kB
posthog-react-native/lib/posthog-react-native/src/types.js 90 B
posthog-react-native/lib/posthog-react-native/src/version.js 123 B
posthog-web/lib/index.cjs.js 17.4 kB
posthog-web/lib/index.esm.js 17.3 kB

compressed-size-action

@dmarticus dmarticus marked this pull request as ready for review November 22, 2024 00:33
matchValue = await this.getFeatureFlag(key, distinctId, {
...options,
onlyEvaluateLocally: true,
sendFeatureFlagEvents: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicitly don't send events when we evaluate the feature flag (since these events won't have response data for the payload), we'll send them manually from this method insstead.

Comment on lines 927 to 953
expect(
await posthog.getFeatureFlagPayload('beta-feature', 'some-distinct-id', undefined, {
personProperties: { region: 'USA', name: 'Aloha' },
})
).toEqual({ variant: 'A' })

// TRICKY: There's now an extra step before events are queued, so need to wait for that to resolve
jest.runOnlyPendingTimers()
await waitForPromises()
await posthog.flush()

expect(mockedFetch).toHaveBeenCalledWith('http://example.com/batch/', expect.any(Object))

expect(getLastBatchEvents()?.[0]).toEqual(
expect.objectContaining({
distinct_id: 'some-distinct-id',
event: '$feature_flag_payload_called',
properties: expect.objectContaining({
$feature_flag: 'beta-feature',
$feature_flag_response: true,
$feature_flag_payload: { variant: 'A' },
locally_evaluated: true,
[`$feature/${'beta-feature'}`]: true,
}),
})
)
mockedFetch.mockClear()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test case that the getFeatureFlagPayload method also sends a feature_flag_called event.

Copy link
Contributor

@havenbarnes havenbarnes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes make sense!

properties: {
$feature_flag: key,
$feature_flag_response: finalResponse,
$feature_flag_payload: finalPayload,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this flag only for local evaluation? I don't think we send this one for any other Mobile SDK, but we do support feature flag payloads

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this flag only for local evaluation?

Not sure what you mean by that; what I did here is add a new property to the feature flag called event that includes the feature_flag_payload anytime a user calls getFeatureFlagPayload.

Copy link
Member

@marandaneto marandaneto Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is that I did not see this new property $feature_flag_payload anywhere else yet, is that new? if so, we'd need to add to other SDKs as well?
JS for example has $feature_flag_payloads (plural with S) but its not used when capturing a $feature_flag_called event.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So my question about local evaluation is if this is only for backend SDKs (only backend SDKs have local evaluation afaik), because I have not found any reference on the JS SDK

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AH I see! Okay this is a good point to raise: yes; right now this fallback on happens for local evaluation on backend SDKs, and we don't include any payload information in these events. In fact, I don't even think we send feature_flag_called events whenever a client-side SDK is used to get payloads, the code just goes like this

    getFeatureFlagPayload(key: string): JsonType {
        const payloads = this.getFlagPayloads()
        return payloads[key]
    }

where getFlagPayloads just loads the payloads from persistence.

    getFlagPayloads(): Record<string, JsonType> {
        const flagPayloads = this.instance.get_property(PERSISTENCE_FEATURE_FLAG_PAYLOADS)
        return flagPayloads || {}
    }

So this is already feature gap between client-side and server side SDKs in more ways than just including the payload – our server-side SDKs send feature_flag_called events on both getFeatureFlag and getFeatureFlagPayload calls. I feel like I should make this documentation clear somewhere if it isn't already, since users could get confused.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't even think we send feature_flag_called events whenever a client-side SDK is used to get payloads

I think the reason is that before you read payloads, you read the flag using getFeatureFlag or isFeatureEnabled.
I don't think it's common to consume getFeatureFlagPayload directly before either of them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I think that's a common pattern for the client-side SDKs that the server-side ones may not follow as much (e.g., the reason I started working on this change at all was because we have a user that's using our python SDK only for the get_feature_flag_payload method).

Okay, so here's what I'm going to do going forward:

  • ship this change to the node SDK
  • keep posthog-js as is

Thanks for chatting about it with me!

@marandaneto
Copy link
Member

@dmarticus for releasing.

@dmarticus dmarticus merged commit 4452a31 into main Nov 26, 2024
4 checks passed
@dmarticus dmarticus deleted the fix/feature-flag-payload-events branch November 26, 2024 19:22
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.

3 participants