Skip to content

Commit bc950fc

Browse files
Vinnlrhelmer
andauthored
Handle both V1 and V2 of Cirrus' data structure (#5508)
* Reapply "MNTOR-3814 - use context to fetch experiment data from Cirrus (#5440)" (#5505) This reverts commit 80e7178. * Revert "handle nimbus user id not set (#5503)" This reverts commit 4de104f. * Handle both V1 and V2 of Cirrus' data structure --------- Co-authored-by: Robert Helmer <[email protected]>
1 parent 47ea9a7 commit bc950fc

File tree

4 files changed

+33
-11
lines changed

4 files changed

+33
-11
lines changed

src/app/functions/server/getExperiments.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ import {
1212
import { ExperimentationId } from "./getExperimentationId";
1313
import { getEnabledFeatureFlags } from "../../../db/tables/featureFlags";
1414

15+
/**
16+
* After we removing the `CirrusV2` flag, we can return the full `ExperimentData`/
17+
* But until then, we can make the old experiment data object look like the new one,
18+
* but we can't backfill the `Enrollments` property.
19+
*/
20+
export type ExperimentData_V2_Or_V2LikeV1 = Partial<ExperimentData> &
21+
Required<Pick<ExperimentData, "Features">>;
22+
1523
/**
1624
* Call the Cirrus sidecar, which returns a list of eligible experiments for the current user.
1725
*
@@ -28,7 +36,7 @@ export async function getExperiments(params: {
2836
locale: string;
2937
countryCode: string;
3038
previewMode: boolean;
31-
}): Promise<ExperimentData> {
39+
}): Promise<ExperimentData_V2_Or_V2LikeV1> {
3240
if (["local"].includes(process.env.APP_ENV ?? "local")) {
3341
return localExperimentData;
3442
}
@@ -78,13 +86,19 @@ export async function getExperiments(params: {
7886
throw new Error(`Cirrus request failed: ${response.statusText}`);
7987
}
8088

81-
const json = await response.json();
89+
// With the `CirrusV2` flag enabled, the response is `ExperimentData`,
90+
// otherwise, it's just `ExperimentData["Features"]`.
91+
const json = (await response.json()) as
92+
| ExperimentData
93+
| ExperimentData["Features"];
8294

83-
let experimentData;
95+
let experimentData: ExperimentData_V2_Or_V2LikeV1;
8496
if (flags.includes("CirrusV2")) {
85-
experimentData = json["Features"];
97+
experimentData = json as ExperimentData;
8698
} else {
87-
experimentData = json;
99+
experimentData = {
100+
Features: json as ExperimentData["Features"],
101+
};
88102
}
89103

90104
return (experimentData as ExperimentData) ?? defaultExperimentData;

src/app/hooks/useGlean.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ export const useGlean = () => {
4444
// Record the `nimbus_*` keys on all events.
4545
// `nimbus_*` is set on every metric, but it's too much work for TypeScript
4646
// to infer that — hence the type assertion.
47-
if (experimentData) {
47+
48+
if (
49+
experimentData &&
50+
typeof experimentData["Enrollments"] !== "undefined"
51+
) {
4852
(data as GleanMetricMap["button"]["click"]).nimbus_user_id =
4953
experimentData["Enrollments"]["nimbus_user_id"];
5054
(data as GleanMetricMap["button"]["click"]).nimbus_app_id =

src/app/layout.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,11 @@ export default async function RootLayout({
7272
previewMode: nimbusPreviewMode === "true",
7373
});
7474

75-
const nimbus_user_id = experimentData["Enrollments"].nimbus_user_id;
76-
if (nimbus_user_id !== experimentationId) {
75+
const nimbus_user_id = experimentData["Enrollments"]?.nimbus_user_id;
76+
if (
77+
typeof nimbus_user_id !== "undefined" &&
78+
nimbus_user_id !== experimentationId
79+
) {
7780
Sentry.captureMessage(
7881
`Nimbus user ID from Cirrus: [${nimbus_user_id}] did not match experimentationId: [${experimentationId}]`,
7982
);

src/contextProviders/experiments.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
"use client";
66

77
import { ReactNode, createContext, useContext } from "react";
8-
import { ExperimentData } from "../telemetry/generated/nimbus/experiments";
8+
import { ExperimentData_V2_Or_V2LikeV1 } from "../app/functions/server/getExperiments";
99

1010
interface ExperimentsProviderProps {
1111
children: ReactNode;
12-
experimentData: ExperimentData;
12+
experimentData: ExperimentData_V2_Or_V2LikeV1;
1313
}
1414

15-
export const ExperimentsContext = createContext<ExperimentData | null>(null);
15+
export const ExperimentsContext =
16+
createContext<ExperimentData_V2_Or_V2LikeV1 | null>(null);
1617

1718
export const ExperimentsProvider = ({
1819
children,

0 commit comments

Comments
 (0)