Skip to content

Commit

Permalink
Merge branch 'master' into feat/automation-branch-typing
Browse files Browse the repository at this point in the history
  • Loading branch information
PClmnt authored Aug 14, 2024
2 parents 6144053 + 5f9ee60 commit 2fcc778
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 8 deletions.
19 changes: 19 additions & 0 deletions packages/backend-core/src/context/mainContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,22 @@ export function getCurrentContext(): ContextMap | undefined {
return undefined
}
}

export function getFeatureFlags<T extends Record<string, any>>(
key: string
): T | undefined {
const context = getCurrentContext()
if (!context) {
return undefined
}
return context.featureFlagCache?.[key] as T
}

export function setFeatureFlags(key: string, value: Record<string, any>) {
const context = getCurrentContext()
if (!context) {
return
}
context.featureFlagCache ??= {}
context.featureFlagCache[key] = value
}
3 changes: 3 additions & 0 deletions packages/backend-core/src/context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ export type ContextMap = {
oauthClient: OAuth2Client
clients: Record<string, GoogleSpreadsheet>
}
featureFlagCache?: {
[key: string]: Record<string, any>
}
}
28 changes: 21 additions & 7 deletions packages/backend-core/src/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export function init(opts?: PostHogOptions) {
}
}

export function shutdown() {
posthog?.shutdown()
}

export abstract class Flag<T> {
static boolean(defaultValue: boolean): Flag<boolean> {
return new BooleanFlag(defaultValue)
Expand Down Expand Up @@ -87,7 +91,14 @@ class NumberFlag extends Flag<number> {
}

export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
constructor(private readonly flagSchema: T) {}
// This is used to safely cache flags sets in the current request context.
// Because multiple sets could theoretically exist, we don't want the cache of
// one to leak into another.
private readonly setId: string

constructor(private readonly flagSchema: T) {
this.setId = crypto.randomUUID()
}

defaults(): FlagValues<T> {
return Object.keys(this.flagSchema).reduce((acc, key) => {
Expand Down Expand Up @@ -119,6 +130,12 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {

async fetch(ctx?: UserCtx): Promise<FlagValues<T>> {
return await tracer.trace("features.fetch", async span => {
const cachedFlags = context.getFeatureFlags<FlagValues<T>>(this.setId)
if (cachedFlags) {
span?.addTags({ fromCache: true })
return cachedFlags
}

const tags: Record<string, any> = {}
const flagValues = this.defaults()
const currentTenantId = context.getTenantId()
Expand Down Expand Up @@ -187,10 +204,7 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
tags[`identity.tenantId`] = identity?.tenantId
tags[`identity._id`] = identity?._id

// Until we're confident this performs well, we're only enabling it in QA
// and test environments.
const usePosthog = env.isTest() || env.isQA()
if (usePosthog && posthog && identity?.type === IdentityType.USER) {
if (posthog && identity?.type === IdentityType.USER) {
tags[`readFromPostHog`] = true

const personProperties: Record<string, string> = {}
Expand All @@ -204,7 +218,6 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
personProperties,
}
)
console.log("posthog flags", JSON.stringify(posthogFlags))

for (const [name, value] of Object.entries(posthogFlags.featureFlags)) {
if (!this.isFlagName(name)) {
Expand Down Expand Up @@ -236,6 +249,7 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
}
}

context.setFeatureFlags(this.setId, flagValues)
for (const [key, value] of Object.entries(flagValues)) {
tags[`flags.${key}.value`] = value
}
Expand All @@ -255,5 +269,5 @@ export const flags = new FlagSet({
GOOGLE_SHEETS: Flag.boolean(false),
USER_GROUPS: Flag.boolean(false),
ONBOARDING_TOUR: Flag.boolean(false),
DEFAULT_VALUES: Flag.boolean(true),
DEFAULT_VALUES: Flag.boolean(false),
})
4 changes: 3 additions & 1 deletion packages/backend-core/src/features/tests/features.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IdentityContext, IdentityType, UserCtx } from "@budibase/types"
import { Flag, FlagSet, FlagValues, init } from "../"
import { Flag, FlagSet, FlagValues, init, shutdown } from "../"
import { context } from "../.."
import environment, { withEnv } from "../../environment"
import nodeFetch from "node-fetch"
Expand Down Expand Up @@ -197,6 +197,8 @@ describe("feature flags", () => {
throw new Error("No expected value")
}
})

shutdown()
})
}
)
Expand Down

0 comments on commit 2fcc778

Please sign in to comment.