Skip to content

Commit 8ee8900

Browse files
committed
perf(webapp): prune the webhook delivery detail lookup to its partition
The delivery detail point lookup queried WebhookDelivery by id and environment only. The table is RANGE-partitioned on createdAt, so with no createdAt predicate Postgres cannot prune and probes every daily partition. Thread the row's createdAt (the list the user navigated from already has it) through to the lookup as a narrow bounding window so it prunes to the row's partition. Direct links with no timestamp fall back to the unbounded query.
1 parent 8c42b04 commit 8ee8900

7 files changed

Lines changed: 53 additions & 5 deletions

File tree

apps/webapp/app/components/webhookDeliveries/v1/DeliveriesTable.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ export function DeliveriesTable({
113113
organization,
114114
project,
115115
environment,
116-
delivery.friendlyId
116+
delivery.friendlyId,
117+
delivery.createdAt
117118
);
118119

119120
return (

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@ export class WebhookDeliveryDetailPresenter {
4949
projectId,
5050
environmentId,
5151
deliveryFriendlyId,
52+
createdAt,
5253
}: {
5354
organizationId: string;
5455
projectId: string;
5556
environmentId: string;
5657
deliveryFriendlyId: string;
58+
createdAt?: Date;
5759
}): Promise<WebhookDeliveryDetail | null> {
5860
const repository = webhookDeliveriesRepository({
5961
clickhouse: this.clickhouse,
@@ -65,6 +67,7 @@ export class WebhookDeliveryDetailPresenter {
6567
projectId,
6668
environmentId,
6769
friendlyId: deliveryFriendlyId,
70+
createdAt,
6871
});
6972

7073
if (!delivery) {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,13 @@ function ConsoleFeedList({
647647
{visibleDeliveries.map((delivery) => (
648648
<Link
649649
key={delivery.id}
650-
to={v3WebhookDeliveryPath(organization, project, environment, delivery.friendlyId)}
650+
to={v3WebhookDeliveryPath(
651+
organization,
652+
project,
653+
environment,
654+
delivery.friendlyId,
655+
delivery.createdAt
656+
)}
651657
className="flex flex-col gap-1 border-b border-grid-dimmed px-3 py-2 hover:bg-charcoal-800"
652658
>
653659
<div className="flex items-center justify-between gap-2">

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,17 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
9797
"standard"
9898
);
9999

100+
const atParam = new URL(request.url).searchParams.get("at");
101+
const atMs = atParam ? Number(atParam) : NaN;
102+
const createdAt = Number.isFinite(atMs) ? new Date(atMs) : undefined;
103+
100104
const presenter = new WebhookDeliveryDetailPresenter($replica, clickhouse);
101105
const delivery = await presenter.call({
102106
organizationId: project.organizationId,
103107
projectId: project.id,
104108
environmentId: environment.id,
105109
deliveryFriendlyId: deliveryParam,
110+
createdAt,
106111
});
107112

108113
const rawEventJson =

apps/webapp/app/services/webhookDeliveriesRepository/clickhouseWebhookDeliveriesRepository.server.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ type DeliveryCursorRow = { deliveryId: string; createdAt: number };
1818

1919
const WEBHOOK_DELIVERY_ID_PREFIX = "whd_";
2020

21+
/**
22+
* Half-width of the `createdAt` window used to partition-prune a delivery point lookup. Wide enough to
23+
* absorb millisecond/microsecond rounding between the caller's timestamp and the stored value, narrow
24+
* enough that the query still prunes to one (occasionally two, across a midnight boundary) daily partition.
25+
*/
26+
const PARTITION_PRUNE_SLOP_MS = 1_000;
27+
2128
const DELIVERY_DETAIL_SELECT = {
2229
id: true,
2330
friendlyId: true,
@@ -281,14 +288,30 @@ export class ClickHouseWebhookDeliveriesRepository implements IWebhookDeliveries
281288
* A point lookup: pure Postgres, never ClickHouse. `friendlyId` is `whd_` + the row id, so we
282289
* strip the prefix and hit the composite-PK index (scoped by environment). ClickHouse is for
283290
* aggregations and for filtering/ordering a list into ids, never for selecting a row's columns.
291+
*
292+
* `WebhookDelivery` is RANGE-partitioned on `createdAt`, so a bare `id` predicate can't prune and
293+
* probes every partition. When the caller supplies `createdAt` (the list row it came from has it),
294+
* bound the query to a narrow window around it so Postgres prunes to the row's partition. The id is
295+
* globally unique, so the window only prunes; it never changes which row is returned.
284296
*/
285297
async getDelivery(options: GetWebhookDeliveryOptions): Promise<DetailedWebhookDelivery | null> {
286298
const id = options.friendlyId.startsWith(WEBHOOK_DELIVERY_ID_PREFIX)
287299
? options.friendlyId.slice(WEBHOOK_DELIVERY_ID_PREFIX.length)
288300
: options.friendlyId;
289301

290302
return this.options.prisma.webhookDelivery.findFirst({
291-
where: { id, runtimeEnvironmentId: options.environmentId },
303+
where: {
304+
id,
305+
runtimeEnvironmentId: options.environmentId,
306+
...(options.createdAt
307+
? {
308+
createdAt: {
309+
gte: new Date(options.createdAt.getTime() - PARTITION_PRUNE_SLOP_MS),
310+
lte: new Date(options.createdAt.getTime() + PARTITION_PRUNE_SLOP_MS),
311+
},
312+
}
313+
: {}),
314+
},
292315
select: DELIVERY_DETAIL_SELECT,
293316
});
294317
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ export type GetWebhookDeliveryOptions = {
8383
projectId: string;
8484
environmentId: string;
8585
friendlyId: string;
86+
/**
87+
* The delivery's `createdAt`, when the caller already has it (e.g. from the
88+
* list row it navigated from). `WebhookDelivery` is RANGE-partitioned on
89+
* `createdAt`, so supplying it lets the point lookup prune to the row's
90+
* partition instead of probing every partition. Omit for a direct link with
91+
* no timestamp; the lookup still succeeds, it just cannot prune.
92+
*/
93+
createdAt?: Date;
8694
};
8795

8896
export type GetDeliveriesByFriendlyIdsOptions = {

apps/webapp/app/utils/pathBuilder.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,15 @@ export function v3WebhookDeliveryPath(
426426
organization: OrgForPath,
427427
project: ProjectForPath,
428428
environment: EnvironmentForPath,
429-
deliveryFriendlyId: string
429+
deliveryFriendlyId: string,
430+
createdAt?: Date
430431
) {
431-
return `${v3EnvironmentPath(
432+
const base = `${v3EnvironmentPath(
432433
organization,
433434
project,
434435
environment
435436
)}/webhooks/deliveries/${encodeURIComponent(deliveryFriendlyId)}`;
437+
return createdAt ? `${base}?at=${createdAt.getTime()}` : base;
436438
}
437439

438440
export function v3WebhookEndpointPath(

0 commit comments

Comments
 (0)