Skip to content

Commit bc768cc

Browse files
committed
FeatureFlag rename to singular and add multiple flags function
1 parent 0674d74 commit bc768cc

File tree

5 files changed

+77
-26
lines changed

5 files changed

+77
-26
lines changed

apps/webapp/app/presenters/v3/RegionsPresenter.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type Project } from "~/models/project.server";
22
import { type User } from "~/models/user.server";
3-
import { FEATURE_FLAG, makeFlags } from "~/v3/featureFlags.server";
3+
import { FEATURE_FLAG, makeFlag } from "~/v3/featureFlags.server";
44
import { BasePresenter } from "./basePresenter.server";
55
import { getCurrentPlan } from "~/services/platform.v3.server";
66

@@ -48,7 +48,7 @@ export class RegionsPresenter extends BasePresenter {
4848
throw new Error("Project not found");
4949
}
5050

51-
const getFlag = makeFlags(this._replica);
51+
const getFlag = makeFlag(this._replica);
5252
const defaultWorkerInstanceGroupId = await getFlag({
5353
key: FEATURE_FLAG.defaultWorkerInstanceGroupId,
5454
});

apps/webapp/app/services/runsRepository/runsRepository.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import parseDuration from "parse-duration";
88
import { z } from "zod";
99
import { timeFilters } from "~/components/runs/v3/SharedFilters";
1010
import { type PrismaClient, type PrismaClientOrTransaction } from "~/db.server";
11-
import { FEATURE_FLAG, makeFlags } from "~/v3/featureFlags.server";
11+
import { FEATURE_FLAG, makeFlag } from "~/v3/featureFlags.server";
1212
import { startActiveSpan } from "~/v3/tracer.server";
1313
import { logger } from "../logger.server";
1414
import { ClickHouseRunsRepository } from "./clickhouseRunsRepository.server";
@@ -163,7 +163,7 @@ export class RunsRepository implements IRunsRepository {
163163

164164
async #getRepository(): Promise<IRunsRepository> {
165165
return startActiveSpan("runsRepository.getRepository", async (span) => {
166-
const getFlag = makeFlags(this.options.prisma);
166+
const getFlag = makeFlag(this.options.prisma);
167167
const runsListRepository = await getFlag({
168168
key: FEATURE_FLAG.runsListRepository,
169169
defaultValue: this.defaultRepository,

apps/webapp/app/v3/eventRepository/index.server.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {
55
clickhouseEventRepositoryV2,
66
} from "./clickhouseEventRepositoryInstance.server";
77
import { IEventRepository, TraceEventOptions } from "./eventRepository.types";
8-
import { prisma } from "~/db.server";
8+
import { prisma } from "~/db.server";
99
import { logger } from "~/services/logger.server";
10-
import { FEATURE_FLAG, flags } from "../featureFlags.server";
10+
import { FEATURE_FLAG, flag } from "../featureFlags.server";
1111
import { getTaskEventStore } from "../taskEventStore.server";
1212

1313
export function resolveEventRepositoryForStore(store: string | undefined): IEventRepository {
@@ -24,13 +24,13 @@ export function resolveEventRepositoryForStore(store: string | undefined): IEven
2424
return eventRepository;
2525
}
2626

27-
export const EVENT_STORE_TYPES = {
28-
POSTGRES: "postgres",
29-
CLICKHOUSE: "clickhouse",
30-
CLICKHOUSE_V2: "clickhouse_v2",
31-
} as const;
27+
export const EVENT_STORE_TYPES = {
28+
POSTGRES: "postgres",
29+
CLICKHOUSE: "clickhouse",
30+
CLICKHOUSE_V2: "clickhouse_v2",
31+
} as const;
3232

33-
export type EventStoreType = typeof EVENT_STORE_TYPES[keyof typeof EVENT_STORE_TYPES];
33+
export type EventStoreType = (typeof EVENT_STORE_TYPES)[keyof typeof EVENT_STORE_TYPES];
3434

3535
export async function getConfiguredEventRepository(
3636
organizationId: string
@@ -122,7 +122,7 @@ export async function getV3EventRepository(
122122
async function resolveTaskEventRepositoryFlag(
123123
featureFlags: Record<string, unknown> | undefined
124124
): Promise<"clickhouse" | "clickhouse_v2" | "postgres"> {
125-
const flag = await flags({
125+
const flag = await flag({
126126
key: FEATURE_FLAG.taskEventRepository,
127127
defaultValue: env.EVENT_REPOSITORY_DEFAULT_STORE,
128128
overrides: featureFlags,

apps/webapp/app/v3/featureFlags.server.ts

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ export type FlagsOptions<T extends FeatureFlagKey> = {
2525
overrides?: Record<string, unknown>;
2626
};
2727

28-
export function makeFlags(_prisma: PrismaClientOrTransaction = prisma) {
29-
function flags<T extends FeatureFlagKey>(
28+
export function makeFlag(_prisma: PrismaClientOrTransaction = prisma) {
29+
function flag<T extends FeatureFlagKey>(
3030
opts: FlagsOptions<T> & { defaultValue: z.infer<(typeof FeatureFlagCatalog)[T]> }
3131
): Promise<z.infer<(typeof FeatureFlagCatalog)[T]>>;
32-
function flags<T extends FeatureFlagKey>(
32+
function flag<T extends FeatureFlagKey>(
3333
opts: FlagsOptions<T>
3434
): Promise<z.infer<(typeof FeatureFlagCatalog)[T]> | undefined>;
35-
async function flags<T extends FeatureFlagKey>(
35+
async function flag<T extends FeatureFlagKey>(
3636
opts: FlagsOptions<T>
3737
): Promise<z.infer<(typeof FeatureFlagCatalog)[T]> | undefined> {
3838
const value = await _prisma.featureFlag.findUnique({
@@ -60,11 +60,11 @@ export function makeFlags(_prisma: PrismaClientOrTransaction = prisma) {
6060
return parsed.data;
6161
}
6262

63-
return flags;
63+
return flag;
6464
}
6565

66-
export function makeSetFlags(_prisma: PrismaClientOrTransaction = prisma) {
67-
return async function setFlags<T extends FeatureFlagKey>(
66+
export function makeSetFlag(_prisma: PrismaClientOrTransaction = prisma) {
67+
return async function setFlag<T extends FeatureFlagKey>(
6868
opts: FlagsOptions<T> & { value: z.infer<(typeof FeatureFlagCatalog)[T]> }
6969
): Promise<void> {
7070
await _prisma.featureFlag.upsert({
@@ -82,8 +82,59 @@ export function makeSetFlags(_prisma: PrismaClientOrTransaction = prisma) {
8282
};
8383
}
8484

85+
export type AllFlagsOptions = {
86+
defaultValues?: Partial<FeatureFlagCatalog>;
87+
overrides?: Record<string, unknown>;
88+
};
89+
90+
export function makeFlags(_prisma: PrismaClientOrTransaction = prisma) {
91+
return async function flags(options?: AllFlagsOptions): Promise<Partial<FeatureFlagCatalog>> {
92+
const rows = await _prisma.featureFlag.findMany();
93+
94+
// Build a map of key -> value from database
95+
const dbValues = new Map<string, unknown>();
96+
for (const row of rows) {
97+
dbValues.set(row.key, row.value);
98+
}
99+
100+
const result: Partial<FeatureFlagCatalog> = {};
101+
102+
// Process each flag in the catalog
103+
for (const key of Object.keys(FeatureFlagCatalog) as FeatureFlagKey[]) {
104+
const schema = FeatureFlagCatalog[key];
105+
106+
// Priority: overrides > database > defaultValues
107+
if (options?.overrides?.[key] !== undefined) {
108+
const parsed = schema.safeParse(options.overrides[key]);
109+
if (parsed.success) {
110+
(result as any)[key] = parsed.data;
111+
continue;
112+
}
113+
}
114+
115+
if (dbValues.has(key)) {
116+
const parsed = schema.safeParse(dbValues.get(key));
117+
if (parsed.success) {
118+
(result as any)[key] = parsed.data;
119+
continue;
120+
}
121+
}
122+
123+
if (options?.defaultValues?.[key] !== undefined) {
124+
const parsed = schema.safeParse(options.defaultValues[key]);
125+
if (parsed.success) {
126+
(result as any)[key] = parsed.data;
127+
}
128+
}
129+
}
130+
131+
return result;
132+
};
133+
}
134+
135+
export const flag = makeFlag();
85136
export const flags = makeFlags();
86-
export const setFlags = makeSetFlags();
137+
export const setFlag = makeSetFlag();
87138

88139
// Create a Zod schema from the existing catalog
89140
export const FeatureFlagCatalogSchema = z.object(FeatureFlagCatalog);
@@ -112,7 +163,7 @@ export function makeSetMultipleFlags(_prisma: PrismaClientOrTransaction = prisma
112163
return async function setMultipleFlags(
113164
flags: Partial<z.infer<typeof FeatureFlagCatalogSchema>>
114165
): Promise<{ key: string; value: any }[]> {
115-
const setFlag = makeSetFlags(_prisma);
166+
const setFlag = makeSetFlag(_prisma);
116167
const updatedFlags: { key: string; value: any }[] = [];
117168

118169
for (const [key, value] of Object.entries(flags)) {

apps/webapp/app/v3/services/worker/workerGroupService.server.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { WorkerInstanceGroup, WorkerInstanceGroupType } from "@trigger.dev/datab
22
import { WithRunEngine } from "../baseService.server";
33
import { WorkerGroupTokenService } from "./workerGroupTokenService.server";
44
import { logger } from "~/services/logger.server";
5-
import { FEATURE_FLAG, makeFlags, makeSetFlags } from "~/v3/featureFlags.server";
5+
import { FEATURE_FLAG, makeFlag, makeSetFlag } from "~/v3/featureFlags.server";
66

77
export class WorkerGroupService extends WithRunEngine {
88
private readonly defaultNamePrefix = "worker_group";
@@ -47,14 +47,14 @@ export class WorkerGroupService extends WithRunEngine {
4747
},
4848
});
4949

50-
const getFlag = makeFlags(this._prisma);
50+
const getFlag = makeFlag(this._prisma);
5151
const defaultWorkerInstanceGroupId = await getFlag({
5252
key: FEATURE_FLAG.defaultWorkerInstanceGroupId,
5353
});
5454

5555
// If there's no global default yet we should set it to the new worker group
5656
if (!defaultWorkerInstanceGroupId) {
57-
const setFlag = makeSetFlags(this._prisma);
57+
const setFlag = makeSetFlag(this._prisma);
5858
await setFlag({
5959
key: FEATURE_FLAG.defaultWorkerInstanceGroupId,
6060
value: workerGroup.id,
@@ -166,7 +166,7 @@ export class WorkerGroupService extends WithRunEngine {
166166
}
167167

168168
async getGlobalDefaultWorkerGroup() {
169-
const flags = makeFlags(this._prisma);
169+
const flags = makeFlag(this._prisma);
170170

171171
const defaultWorkerInstanceGroupId = await flags({
172172
key: FEATURE_FLAG.defaultWorkerInstanceGroupId,

0 commit comments

Comments
 (0)