From 1a51498a836768aa00596d48558b531331b73890 Mon Sep 17 00:00:00 2001 From: coodos Date: Wed, 12 Aug 2026 17:39:24 +0530 Subject: [PATCH] fix: take --- .../api/src/controllers/ConsumerController.ts | 23 +++++++++++- .../api/src/database/entities/Delivery.ts | 2 + ...0-AddDeliveriesSubscriptionCreatedIndex.ts | 37 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 services/awareness-service/api/src/database/migrations/1786492800000-AddDeliveriesSubscriptionCreatedIndex.ts diff --git a/services/awareness-service/api/src/controllers/ConsumerController.ts b/services/awareness-service/api/src/controllers/ConsumerController.ts index 391d4e5c2..501e0c7e2 100644 --- a/services/awareness-service/api/src/controllers/ConsumerController.ts +++ b/services/awareness-service/api/src/controllers/ConsumerController.ts @@ -71,6 +71,21 @@ export function consumerRouter(): Router { ); const deliveries = await AppDataSource.getRepository(Delivery) .createQueryBuilder("d") + // The `payload` snapshot is deliberately excluded: it is a full + // event body per row and nothing here renders it, so selecting it + // would drag every matched row's jsonb out of TOAST for nothing. + .select([ + "d.id", + "d.subscriptionId", + "d.packetId", + "d.status", + "d.attempts", + "d.nextAttemptAt", + "d.lastError", + "d.lastResponseStatus", + "d.createdAt", + "d.deliveredAt", + ]) .innerJoin( Subscription, "s", @@ -78,7 +93,13 @@ export function consumerRouter(): Router { { cid: req.consumer!.id }, ) .orderBy("d.createdAt", "DESC") - .take(limit) + // `limit`, not `take`: with a join present `take` makes TypeORM + // wrap the query in a SELECT DISTINCT over an *unbounded* subquery + // and apply LIMIT only on the outside, so Postgres materialises and + // sorts the consumer's entire delivery history to return 50 rows. + // The join is to subscriptions on its primary key and so cannot + // duplicate rows, which is the only thing that DISTINCT pass buys. + .limit(limit) .getMany(); res.json({ deliveries }); }); diff --git a/services/awareness-service/api/src/database/entities/Delivery.ts b/services/awareness-service/api/src/database/entities/Delivery.ts index 1c0170da2..a78edb9e9 100644 --- a/services/awareness-service/api/src/database/entities/Delivery.ts +++ b/services/awareness-service/api/src/database/entities/Delivery.ts @@ -26,6 +26,8 @@ export type DeliveryStatus = "packetId", "contentHash", ]) +// Serves the consumer dashboard's newest-first delivery list. +@Index("idx_deliveries_subscription_created", ["subscriptionId", "createdAt"]) export class Delivery { @PrimaryGeneratedColumn("uuid") id!: string; diff --git a/services/awareness-service/api/src/database/migrations/1786492800000-AddDeliveriesSubscriptionCreatedIndex.ts b/services/awareness-service/api/src/database/migrations/1786492800000-AddDeliveriesSubscriptionCreatedIndex.ts new file mode 100644 index 000000000..e458a8ca6 --- /dev/null +++ b/services/awareness-service/api/src/database/migrations/1786492800000-AddDeliveriesSubscriptionCreatedIndex.ts @@ -0,0 +1,37 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +/** + * Support `/api/me/deliveries`, which lists a consumer's most recent deliveries + * newest-first. Without a (subscriptionId, createdAt) index that read sorts the + * consumer's entire delivery history on every dashboard load; the existing + * idx_deliveries_subscription can find the rows but cannot supply the ordering. + * + * NOTE for large deployments: `deliveries` is the hottest write table in the + * service and a plain CREATE INDEX holds a SHARE lock - blocking the delivery + * engine's writes - for as long as the build takes. Migrations here run inside + * a single transaction (typeorm's default "all" mode), which rules out + * CONCURRENTLY. So on a big table, build it by hand first: + * + * CREATE INDEX CONCURRENTLY "idx_deliveries_subscription_created" + * ON "deliveries" ("subscriptionId", "createdAt" DESC); + * + * The IF NOT EXISTS below then makes this migration a no-op. + */ +export class AddDeliveriesSubscriptionCreatedIndex1786492800000 + implements MigrationInterface +{ + name = "AddDeliveriesSubscriptionCreatedIndex1786492800000"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE INDEX IF NOT EXISTS "idx_deliveries_subscription_created" + ON "deliveries" ("subscriptionId", "createdAt" DESC)`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP INDEX IF EXISTS "idx_deliveries_subscription_created"`, + ); + } +}