Skip to content

Commit 714e4ec

Browse files
committed
Added queues.list() SDK function
1 parent 323a124 commit 714e4ec

10 files changed

Lines changed: 266 additions & 92 deletions

File tree

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
ClockIcon,
33
HandRaisedIcon,
44
InformationCircleIcon,
5+
RectangleStackIcon,
56
Squares2X2Icon,
67
TagIcon,
78
} from "@heroicons/react/20/solid";
@@ -59,6 +60,8 @@ export function RunIcon({ name, className, spanName }: TaskIconProps) {
5960
return <Squares2X2Icon className={cn(className, "text-text-dimmed")} />;
6061
case "tag":
6162
return <TagIcon className={cn(className, "text-text-dimmed")} />;
63+
case "queue":
64+
return <RectangleStackIcon className={cn(className, "text-purple-500")} />;
6265
//log levels
6366
case "debug":
6467
case "log":

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,35 @@ import { engine } from "~/v3/runEngine.server";
33
import { BasePresenter } from "./basePresenter.server";
44
import { type TaskQueueType } from "@trigger.dev/database";
55
import { assertExhaustive } from "@trigger.dev/core";
6+
import { determineEngineVersion } from "~/v3/engineVersion.server";
67

8+
const DEFAULT_ITEMS_PER_PAGE = 25;
79
export class QueueListPresenter extends BasePresenter {
8-
private readonly ITEMS_PER_PAGE = 25;
10+
private readonly perPage: number;
11+
12+
constructor(perPage: number = DEFAULT_ITEMS_PER_PAGE) {
13+
super();
14+
this.perPage = perPage;
15+
}
916

1017
public async call({
1118
environment,
1219
page,
1320
}: {
1421
environment: AuthenticatedEnvironment;
1522
page: number;
23+
perPage?: number;
1624
}) {
25+
//check the engine is the correct version
26+
const engineVersion = await determineEngineVersion({ environment });
27+
28+
if (engineVersion === "V1") {
29+
return {
30+
success: false as const,
31+
code: "engine-version",
32+
};
33+
}
34+
1735
// Get total count for pagination
1836
const totalQueues = await this._replica.taskQueue.count({
1937
where: {
@@ -22,12 +40,12 @@ export class QueueListPresenter extends BasePresenter {
2240
});
2341

2442
return {
43+
success: true as const,
2544
queues: this.getQueuesWithPagination(environment, page),
2645
pagination: {
2746
currentPage: page,
28-
totalPages: Math.ceil(totalQueues / this.ITEMS_PER_PAGE),
29-
totalItems: totalQueues,
30-
itemsPerPage: this.ITEMS_PER_PAGE,
47+
totalPages: Math.ceil(totalQueues / this.perPage),
48+
count: totalQueues,
3149
},
3250
};
3351
}
@@ -45,8 +63,8 @@ export class QueueListPresenter extends BasePresenter {
4563
orderBy: {
4664
name: "asc",
4765
},
48-
skip: (page - 1) * this.ITEMS_PER_PAGE,
49-
take: this.ITEMS_PER_PAGE,
66+
skip: (page - 1) * this.perPage,
67+
take: this.perPage,
5068
});
5169

5270
const results = await Promise.all([

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

Lines changed: 101 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,15 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
9191

9292
try {
9393
const queueListPresenter = new QueueListPresenter();
94-
const result = await queueListPresenter.call({
94+
const queues = await queueListPresenter.call({
9595
environment,
9696
page,
9797
});
9898

9999
const environmentQueuePresenter = new EnvironmentQueuePresenter();
100100

101101
return typeddefer({
102-
...result,
102+
queues,
103103
environment: environmentQueuePresenter.call(environment),
104104
});
105105
} catch (error) {
@@ -169,7 +169,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
169169
};
170170

171171
export default function Page() {
172-
const { environment, queues, pagination } = useTypedLoaderData<typeof loader>();
172+
const { environment, queues } = useTypedLoaderData<typeof loader>();
173173

174174
const organization = useOrganization();
175175
const env = useEnvironment();
@@ -255,98 +255,113 @@ export default function Page() {
255255
</Suspense>
256256
</div>
257257

258-
<Table containerClassName="border-t">
259-
<TableHeader>
260-
<TableRow>
261-
<TableHeaderCell>Name</TableHeaderCell>
262-
<TableHeaderCell alignment="right">Queued</TableHeaderCell>
263-
<TableHeaderCell alignment="right">Running</TableHeaderCell>
264-
<TableHeaderCell alignment="right">Concurrency limit</TableHeaderCell>
265-
<TableHeaderCell alignment="right">
266-
<span className="sr-only">Pause/resume</span>
267-
</TableHeaderCell>
268-
</TableRow>
269-
</TableHeader>
270-
<TableBody>
271-
<Suspense
272-
fallback={
258+
{queues.success ? (
259+
<>
260+
<Table containerClassName="border-t">
261+
<TableHeader>
273262
<TableRow>
274-
<TableCell colSpan={5}>
275-
<div className="grid place-items-center py-6">
276-
<Spinner />
277-
</div>
278-
</TableCell>
263+
<TableHeaderCell>Name</TableHeaderCell>
264+
<TableHeaderCell alignment="right">Queued</TableHeaderCell>
265+
<TableHeaderCell alignment="right">Running</TableHeaderCell>
266+
<TableHeaderCell alignment="right">Concurrency limit</TableHeaderCell>
267+
<TableHeaderCell alignment="right">
268+
<span className="sr-only">Pause/resume</span>
269+
</TableHeaderCell>
279270
</TableRow>
280-
}
281-
>
282-
<Await
283-
resolve={Promise.all([queues, environment])}
284-
errorElement={<p>Error loading queues</p>}
285-
>
286-
{([queues, environment]) =>
287-
queues.length > 0 ? (
288-
queues.map((queue) => (
289-
<TableRow key={queue.name}>
290-
<TableCell>
291-
<span className="flex items-center gap-2">
292-
{queue.type === "task" ? (
293-
<SimpleTooltip
294-
button={<TaskIcon className="size-4 text-blue-500" />}
295-
content={`This queue was automatically created from your "${queue.name}" task`}
296-
/>
297-
) : (
298-
<SimpleTooltip
299-
button={<RectangleStackIcon className="size-4 text-purple-500" />}
300-
content={`This is a custom queue you added in your code.`}
301-
/>
302-
)}
303-
<span>{queue.name}</span>
304-
</span>
305-
</TableCell>
306-
<TableCell alignment="right">{queue.queued}</TableCell>
307-
<TableCell alignment="right">{queue.running}</TableCell>
308-
<TableCell alignment="right">
309-
{queue.concurrencyLimit ?? (
310-
<span className="text-text-dimmed">
311-
Max ({environment.concurrencyLimit})
312-
</span>
313-
)}
314-
</TableCell>
315-
</TableRow>
316-
))
317-
) : (
271+
</TableHeader>
272+
<TableBody>
273+
<Suspense
274+
fallback={
318275
<TableRow>
319276
<TableCell colSpan={5}>
320-
<div className="grid place-items-center py-6 text-text-dimmed">
321-
No queues found
277+
<div className="grid place-items-center py-6">
278+
<Spinner />
322279
</div>
323280
</TableCell>
324281
</TableRow>
325-
)
326-
}
327-
</Await>
328-
</Suspense>
329-
</TableBody>
330-
</Table>
282+
}
283+
>
284+
<Await
285+
resolve={Promise.all([queues.queues, environment])}
286+
errorElement={<p>Error loading queues</p>}
287+
>
288+
{([q, environment]) =>
289+
q.length > 0 ? (
290+
q.map((queue) => (
291+
<TableRow key={queue.name}>
292+
<TableCell>
293+
<span className="flex items-center gap-2">
294+
{queue.type === "task" ? (
295+
<SimpleTooltip
296+
button={<TaskIcon className="size-4 text-blue-500" />}
297+
content={`This queue was automatically created from your "${queue.name}" task`}
298+
/>
299+
) : (
300+
<SimpleTooltip
301+
button={
302+
<RectangleStackIcon className="size-4 text-purple-500" />
303+
}
304+
content={`This is a custom queue you added in your code.`}
305+
/>
306+
)}
307+
<span>{queue.name}</span>
308+
</span>
309+
</TableCell>
310+
<TableCell alignment="right">{queue.queued}</TableCell>
311+
<TableCell alignment="right">{queue.running}</TableCell>
312+
<TableCell alignment="right">
313+
{queue.concurrencyLimit ?? (
314+
<span className="text-text-dimmed">
315+
Max ({environment.concurrencyLimit})
316+
</span>
317+
)}
318+
</TableCell>
319+
</TableRow>
320+
))
321+
) : (
322+
<TableRow>
323+
<TableCell colSpan={5}>
324+
<div className="grid place-items-center py-6 text-text-dimmed">
325+
No queues found
326+
</div>
327+
</TableCell>
328+
</TableRow>
329+
)
330+
}
331+
</Await>
332+
</Suspense>
333+
</TableBody>
334+
</Table>
331335

332-
<div
333-
className={cn(
334-
"grid h-fit max-h-full min-h-full overflow-x-auto",
335-
pagination.totalPages > 1 ? "grid-rows-[1fr_auto]" : "grid-rows-[1fr]"
336-
)}
337-
>
338-
<div
339-
className={cn(
340-
"flex min-h-full",
341-
pagination.totalPages > 1 && "justify-end border-t border-grid-dimmed px-2 py-3"
342-
)}
343-
>
344-
<PaginationControls
345-
currentPage={pagination.currentPage}
346-
totalPages={pagination.totalPages}
347-
/>
336+
<div
337+
className={cn(
338+
"grid h-fit max-h-full min-h-full overflow-x-auto",
339+
queues.pagination.totalPages > 1 ? "grid-rows-[1fr_auto]" : "grid-rows-[1fr]"
340+
)}
341+
>
342+
<div
343+
className={cn(
344+
"flex min-h-full",
345+
queues.pagination.totalPages > 1 &&
346+
"justify-end border-t border-grid-dimmed px-2 py-3"
347+
)}
348+
>
349+
<PaginationControls
350+
currentPage={queues.pagination.currentPage}
351+
totalPages={queues.pagination.totalPages}
352+
/>
353+
</div>
354+
</div>
355+
</>
356+
) : (
357+
<div className="grid place-items-center py-6 text-text-dimmed">
358+
<p>
359+
{queues.code === "engine-version"
360+
? "Please upgrade your engine to v3 to use queues."
361+
: "Something went wrong"}
362+
</p>
348363
</div>
349-
</div>
364+
)}
350365
</div>
351366
</PageBody>
352367
</PageContainer>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { json } from "@remix-run/server-runtime";
2+
import { z } from "zod";
3+
import { QueueListPresenter } from "~/presenters/v3/QueueListPresenter.server";
4+
import { createLoaderApiRoute } from "~/services/routeBuilders/apiBuilder.server";
5+
import { ServiceValidationError } from "~/v3/services/baseService.server";
6+
7+
const SearchParamsSchema = z.object({
8+
page: z.coerce.number().int().positive().optional(),
9+
perPage: z.coerce.number().int().positive().optional(),
10+
});
11+
12+
export const loader = createLoaderApiRoute(
13+
{
14+
searchParams: SearchParamsSchema,
15+
findResource: async () => 1, // This is a dummy function, we don't need to find a resource
16+
},
17+
async ({ searchParams, authentication }) => {
18+
const service = new QueueListPresenter(searchParams.perPage);
19+
20+
try {
21+
const result = await service.call({
22+
environment: authentication.environment,
23+
page: searchParams.page ?? 1,
24+
});
25+
26+
if (!result.success) {
27+
return json({ error: result.code }, { status: 400 });
28+
}
29+
30+
const queues = await result.queues;
31+
return json({ data: queues, pagination: result.pagination }, { status: 200 });
32+
} catch (error) {
33+
if (error instanceof ServiceValidationError) {
34+
return json({ error: error.message }, { status: 422 });
35+
}
36+
37+
return json(
38+
{ error: error instanceof Error ? error.message : "Internal Server Error" },
39+
{ status: 500 }
40+
);
41+
}
42+
}
43+
);

packages/core/src/v3/apiClient/index.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import {
1818
EnvironmentVariableResponseBody,
1919
EnvironmentVariableValue,
2020
EnvironmentVariables,
21+
ListQueueOptions,
2122
ListRunResponseItem,
2223
ListScheduleOptions,
24+
QueueItem,
2325
ReplayRunResponse,
2426
RescheduleRunRequestBody,
2527
RetrieveBatchV2Response,
@@ -716,6 +718,32 @@ export class ApiClient {
716718
);
717719
}
718720

721+
listQueues(options?: ListQueueOptions, requestOptions?: ZodFetchOptions) {
722+
const searchParams = new URLSearchParams();
723+
724+
if (options?.page) {
725+
searchParams.append("page", options.page.toString());
726+
}
727+
728+
if (options?.perPage) {
729+
searchParams.append("perPage", options.perPage.toString());
730+
}
731+
732+
return zodfetchOffsetLimitPage(
733+
QueueItem,
734+
`${this.baseUrl}/api/v1/queues`,
735+
{
736+
page: options?.page,
737+
limit: options?.perPage,
738+
},
739+
{
740+
method: "GET",
741+
headers: this.#getHeaders(false),
742+
},
743+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
744+
);
745+
}
746+
719747
subscribeToRun<TRunTypes extends AnyRunTypes>(
720748
runId: string,
721749
options?: {

packages/core/src/v3/schemas/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ export * from "./runEngine.js";
1414
export * from "./webhooks.js";
1515
export * from "./checkpoints.js";
1616
export * from "./warmStart.js";
17+
export * from "./queues.js";

0 commit comments

Comments
 (0)