Skip to content

Commit 1a8b336

Browse files
Merge branch 'main' into fix/sdk-stream-root-fallback
2 parents 97f266f + 4093883 commit 1a8b336

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1417
-206
lines changed

.changeset/ai-sdk-v6-support.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

.changeset/bright-keys-shine.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

.changeset/gentle-streams-flow.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/thirty-trainers-reflect.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

apps/webapp/app/components/runs/v3/ReplayRunDialog.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ function ReplayForm({
201201
tags,
202202
version,
203203
machine,
204+
prioritySeconds,
204205
},
205206
] = useForm({
206207
id: "replay-task",
@@ -499,6 +500,12 @@ function ReplayForm({
499500
<Hint>Delays run by a specific duration.</Hint>
500501
<FormError id={delaySeconds.errorId}>{delaySeconds.error}</FormError>
501502
</InputGroup>
503+
<InputGroup>
504+
<Label variant="small">Priority</Label>
505+
<DurationPicker name={prioritySeconds.name} id={prioritySeconds.id} />
506+
<Hint>Sets the priority of the run. Higher values mean higher priority.</Hint>
507+
<FormError id={prioritySeconds.errorId}>{prioritySeconds.error}</FormError>
508+
</InputGroup>
502509
<InputGroup>
503510
<Label variant="small">TTL</Label>
504511
<DurationPicker

apps/webapp/app/models/project.server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { nanoid, customAlphabet } from "nanoid";
22
import slug from "slug";
3-
import { prisma } from "~/db.server";
3+
import { $replica, prisma } from "~/db.server";
44
import type { Project } from "@trigger.dev/database";
55
import { Organization, createEnvironment } from "./organization.server";
66
import { env } from "~/env.server";
@@ -135,7 +135,7 @@ export async function createProject(
135135

136136
export async function findProjectBySlug(orgSlug: string, projectSlug: string, userId: string) {
137137
// Find the project scoped to the organization, making sure the user belongs to that org
138-
return await prisma.project.findFirst({
138+
return await $replica.project.findFirst({
139139
where: {
140140
slug: projectSlug,
141141
organization: {
@@ -148,7 +148,7 @@ export async function findProjectBySlug(orgSlug: string, projectSlug: string, us
148148

149149
export async function findProjectByRef(externalRef: string, userId: string) {
150150
// Find the project scoped to the organization, making sure the user belongs to that org
151-
return await prisma.project.findFirst({
151+
return await $replica.project.findFirst({
152152
where: {
153153
externalRef,
154154
organization: {

apps/webapp/app/models/runtimeEnvironment.server.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { AuthenticatedEnvironment } from "@internal/run-engine";
22
import type { Prisma, PrismaClientOrTransaction, RuntimeEnvironment } from "@trigger.dev/database";
3-
import { prisma } from "~/db.server";
3+
import { $replica, prisma } from "~/db.server";
44
import { logger } from "~/services/logger.server";
55
import { getUsername } from "~/utils/username";
66
import { sanitizeBranchName } from "~/v3/gitBranch";
@@ -11,7 +11,7 @@ export async function findEnvironmentByApiKey(
1111
apiKey: string,
1212
branchName: string | undefined
1313
): Promise<AuthenticatedEnvironment | null> {
14-
const environment = await prisma.runtimeEnvironment.findFirst({
14+
const environment = await $replica.runtimeEnvironment.findFirst({
1515
where: {
1616
apiKey,
1717
},
@@ -67,7 +67,7 @@ export async function findEnvironmentByPublicApiKey(
6767
apiKey: string,
6868
branchName: string | undefined
6969
): Promise<AuthenticatedEnvironment | null> {
70-
const environment = await prisma.runtimeEnvironment.findFirst({
70+
const environment = await $replica.runtimeEnvironment.findFirst({
7171
where: {
7272
pkApiKey: apiKey,
7373
},
@@ -89,7 +89,7 @@ export async function findEnvironmentByPublicApiKey(
8989
export async function findEnvironmentById(
9090
id: string
9191
): Promise<(AuthenticatedEnvironment & { parentEnvironment: { apiKey: string } | null }) | null> {
92-
const environment = await prisma.runtimeEnvironment.findFirst({
92+
const environment = await $replica.runtimeEnvironment.findFirst({
9393
where: {
9494
id,
9595
},
@@ -118,7 +118,7 @@ export async function findEnvironmentBySlug(
118118
envSlug: string,
119119
userId: string
120120
): Promise<AuthenticatedEnvironment | null> {
121-
return prisma.runtimeEnvironment.findFirst({
121+
return $replica.runtimeEnvironment.findFirst({
122122
where: {
123123
projectId: projectId,
124124
slug: envSlug,
@@ -148,7 +148,7 @@ export async function findEnvironmentFromRun(
148148
runId: string,
149149
tx?: PrismaClientOrTransaction
150150
): Promise<AuthenticatedEnvironment | null> {
151-
const taskRun = await (tx ?? prisma).taskRun.findFirst({
151+
const taskRun = await (tx ?? $replica).taskRun.findFirst({
152152
where: {
153153
id: runId,
154154
},
@@ -223,7 +223,7 @@ export async function disconnectSession(environmentId: string) {
223223
}
224224

225225
export async function findLatestSession(environmentId: string) {
226-
const session = await prisma.runtimeEnvironmentSession.findFirst({
226+
const session = await $replica.runtimeEnvironmentSession.findFirst({
227227
where: {
228228
environmentId,
229229
},
@@ -280,7 +280,7 @@ export async function findDisplayableEnvironment(
280280
environmentId: string,
281281
userId: string | undefined
282282
) {
283-
const environment = await prisma.runtimeEnvironment.findFirst({
283+
const environment = await $replica.runtimeEnvironment.findFirst({
284284
where: {
285285
id: environmentId,
286286
},

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

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@ export class LimitsPresenter extends BasePresenter {
8383
public async call({
8484
organizationId,
8585
projectId,
86+
environmentId,
8687
environmentApiKey,
8788
}: {
8889
organizationId: string;
8990
projectId: string;
91+
environmentId: string;
9092
environmentApiKey: string;
9193
}): Promise<LimitsResult> {
9294
// Get organization with all limit-related fields
@@ -159,9 +161,9 @@ export class LimitsPresenter extends BasePresenter {
159161
environmentApiKey,
160162
apiRateLimitConfig
161163
);
162-
const batchRateLimitTokens = await getRateLimitRemainingTokens(
163-
"batch",
164-
environmentApiKey,
164+
// Batch rate limiter uses environment ID directly (not hashed) with a different key prefix
165+
const batchRateLimitTokens = await getBatchRateLimitRemainingTokens(
166+
environmentId,
165167
batchRateLimitConfig
166168
);
167169

@@ -419,3 +421,36 @@ async function getRateLimitRemainingTokens(
419421
return null;
420422
}
421423
}
424+
425+
/**
426+
* Query the current remaining tokens for the batch rate limiter.
427+
* The batch rate limiter uses environment ID directly (not hashed) and has a different key prefix.
428+
*/
429+
async function getBatchRateLimitRemainingTokens(
430+
environmentId: string,
431+
config: RateLimiterConfig
432+
): Promise<number | null> {
433+
try {
434+
// Create a Ratelimit instance with the same configuration as the batch rate limiter
435+
const limiter = createLimiterFromConfig(config);
436+
const ratelimit = new Ratelimit({
437+
redis: rateLimitRedisClient,
438+
limiter,
439+
ephemeralCache: new Map(),
440+
analytics: false,
441+
// The batch rate limiter uses "ratelimit:batch" as keyPrefix in RateLimiter,
442+
// which adds another "ratelimit:" prefix, resulting in "ratelimit:ratelimit:batch"
443+
prefix: `ratelimit:ratelimit:batch`,
444+
});
445+
446+
// Batch rate limiter uses environment ID directly (not hashed)
447+
const remaining = await ratelimit.getRemaining(environmentId);
448+
return remaining;
449+
} catch (error) {
450+
logger.warn("Failed to get batch rate limit remaining tokens", {
451+
environmentId,
452+
error: error instanceof Error ? error.message : String(error),
453+
});
454+
return null;
455+
}
456+
}

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.limits/route.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
8181
presenter.call({
8282
organizationId: project.organizationId,
8383
projectId: project.id,
84+
environmentId: environment.id,
8485
environmentApiKey: environment.apiKey,
8586
})
8687
);

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ function StandardTaskForm({
409409
tags,
410410
version,
411411
machine,
412+
prioritySeconds,
412413
},
413414
] = useForm({
414415
id: "test-task",
@@ -730,6 +731,12 @@ function StandardTaskForm({
730731
<Hint>Delays run by a specific duration.</Hint>
731732
<FormError id={delaySeconds.errorId}>{delaySeconds.error}</FormError>
732733
</InputGroup>
734+
<InputGroup>
735+
<Label variant="small">Priority</Label>
736+
<DurationPicker name={prioritySeconds.name} id={prioritySeconds.id} />
737+
<Hint>Sets the priority of the run. Higher values mean higher priority.</Hint>
738+
<FormError id={prioritySeconds.errorId}>{prioritySeconds.error}</FormError>
739+
</InputGroup>
733740
<InputGroup>
734741
<Label variant="small">TTL</Label>
735742
<DurationPicker
@@ -872,6 +879,7 @@ function ScheduledTaskForm({
872879
tags,
873880
version,
874881
machine,
882+
prioritySeconds,
875883
},
876884
] = useForm({
877885
id: "test-task-scheduled",
@@ -1237,6 +1245,14 @@ function ScheduledTaskForm({
12371245
<Hint>Limits concurrency by creating a separate queue for each value of the key.</Hint>
12381246
<FormError id={concurrencyKey.errorId}>{concurrencyKey.error}</FormError>
12391247
</InputGroup>
1248+
<InputGroup>
1249+
<Label htmlFor={prioritySeconds.id} variant="small">
1250+
Priority
1251+
</Label>
1252+
<DurationPicker name={prioritySeconds.name} id={prioritySeconds.id} />
1253+
<Hint>Sets the priority of the run. Higher values mean higher priority.</Hint>
1254+
<FormError id={prioritySeconds.errorId}>{prioritySeconds.error}</FormError>
1255+
</InputGroup>
12401256
<InputGroup>
12411257
<Label htmlFor={ttlSeconds.id} variant="small">
12421258
TTL

0 commit comments

Comments
 (0)