Skip to content

Commit 88105fe

Browse files
authored
Merge pull request dubinc#2292 from dubinc/improve-domain-patch
Improve domain update
2 parents 8f3e267 + f8dba4b commit 88105fe

8 files changed

Lines changed: 100 additions & 90 deletions

File tree

apps/web/app/api/cron/domains/update/route.ts

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,24 @@ import { linkCache } from "@/lib/api/links/cache";
44
import { verifyQstashSignature } from "@/lib/cron/verify-qstash";
55
import { recordLink } from "@/lib/tinybird";
66
import { prisma } from "@dub/prisma";
7+
import { Link } from "@dub/prisma/client";
8+
import { linkConstructorSimple } from "@dub/utils";
79
import { z } from "zod";
810

911
export const dynamic = "force-dynamic";
1012

1113
const schema = z.object({
1214
newDomain: z.string(),
1315
oldDomain: z.string(),
14-
workspaceId: z.string(),
15-
page: z.number(),
1616
});
1717

18-
const pageSize = 100;
19-
2018
// POST /api/cron/domains/update
2119
export async function POST(req: Request) {
2220
try {
2321
const rawBody = await req.text();
2422
await verifyQstashSignature({ req, rawBody });
2523

26-
const { newDomain, oldDomain, workspaceId, page } = schema.parse(
27-
JSON.parse(rawBody),
28-
);
24+
const { newDomain, oldDomain } = schema.parse(JSON.parse(rawBody));
2925

3026
const newDomainRecord = await prisma.domain.findUnique({
3127
where: {
@@ -37,46 +33,85 @@ export async function POST(req: Request) {
3733
return new Response(`Domain ${newDomain} not found. Skipping update...`);
3834
}
3935

40-
const links = await prisma.link.findMany({
36+
const linksToUpdate = await prisma.link.findMany({
4137
where: {
38+
domain: oldDomain,
39+
},
40+
take: 100,
41+
});
42+
43+
if (linksToUpdate.length === 0) {
44+
return new Response("No more links to update. Exiting...");
45+
}
46+
47+
const linkIdsToUpdate = linksToUpdate.map((link) => link.id);
48+
49+
await prisma.link.updateMany({
50+
where: {
51+
id: {
52+
in: linkIdsToUpdate,
53+
},
54+
},
55+
data: {
4256
domain: newDomain,
4357
},
58+
});
59+
60+
const updatedLinks = await prisma.link.findMany({
61+
where: {
62+
id: {
63+
in: linkIdsToUpdate,
64+
},
65+
},
4466
include: {
4567
tags: {
4668
select: {
4769
tag: true,
4870
},
4971
},
5072
},
51-
skip: (page - 1) * pageSize,
52-
take: pageSize,
5373
});
5474

55-
if (links.length === 0) {
56-
return new Response("No more links to update. Exiting...");
57-
}
58-
59-
await Promise.all([
60-
// rename redis keys
61-
linkCache.rename({
62-
links,
63-
oldDomain,
64-
}),
65-
66-
// update links in Tinybird
67-
recordLink(links),
75+
await Promise.allSettled([
76+
// update the `shortLink` field for each of the short links
77+
updateShortLinks(updatedLinks),
78+
// record new link values in Tinybird (dub_links_metadata)
79+
recordLink(updatedLinks),
80+
// expire the redis cache for the old links
81+
linkCache.expireMany(linksToUpdate),
6882
]);
6983

7084
await queueDomainUpdate({
71-
workspaceId,
72-
oldDomain,
7385
newDomain,
74-
page: page + 1,
75-
delay: 2,
86+
oldDomain,
87+
delay: 1,
7688
});
7789

7890
return new Response("Domain's links updated.");
7991
} catch (error) {
8092
return handleAndReturnErrorResponse(error);
8193
}
8294
}
95+
96+
// Update the shortLink column for a list of links
97+
const updateShortLinks = async (
98+
links: Pick<Link, "id" | "domain" | "key">[],
99+
) => {
100+
if (!links || links.length === 0) {
101+
return new Response("No links found.");
102+
}
103+
104+
for (const link of links) {
105+
await prisma.link.update({
106+
where: {
107+
id: link.id,
108+
},
109+
data: {
110+
shortLink: linkConstructorSimple({
111+
domain: link.domain,
112+
key: link.key,
113+
}),
114+
},
115+
});
116+
}
117+
};

apps/web/app/api/domains/[domain]/route.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,8 @@ export const PATCH = withWorkspace(
151151

152152
// trigger the queue to rename the redis keys and update the links in Tinybird
153153
queueDomainUpdate({
154-
workspaceId: workspace.id,
155154
oldDomain: domain,
156155
newDomain: newDomain,
157-
page: 1,
158156
}),
159157
]);
160158
}

apps/web/app/api/domains/route.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from "@/lib/zod/schemas/domains";
1313
import { prisma } from "@dub/prisma";
1414
import { combineWords, DEFAULT_LINK_PROPS, nanoid } from "@dub/utils";
15-
import { Prisma } from "@prisma/client";
15+
import { Link, Prisma } from "@prisma/client";
1616
import { NextResponse } from "next/server";
1717

1818
// GET /api/domains – get all domains for a workspace
@@ -33,40 +33,46 @@ export const GET = withWorkspace(
3333
},
3434
include: {
3535
registeredDomain: true,
36-
...(includeLink && {
37-
links: {
38-
where: {
39-
key: {
40-
in: ["_root", "akoJCU0="],
41-
},
36+
},
37+
take: pageSize,
38+
skip: (page - 1) * pageSize,
39+
});
40+
41+
const links = includeLink
42+
? await prisma.link.findMany({
43+
where: {
44+
key: {
45+
in: ["_root", "akoJCU0="],
46+
},
47+
domain: {
48+
in: domains.map((domain) => domain.slug),
4249
},
43-
include: {
44-
tags: {
45-
select: {
46-
tag: {
47-
select: {
48-
id: true,
49-
name: true,
50-
color: true,
51-
},
52-
},
53-
},
50+
},
51+
include: {
52+
tags: {
53+
select: {
54+
tag: true,
5455
},
5556
},
5657
},
57-
}),
58+
})
59+
: [];
60+
61+
const linkMap = links.reduce(
62+
(acc, link) => {
63+
acc[link.domain] = link;
64+
return acc;
5865
},
59-
take: pageSize,
60-
skip: (page - 1) * pageSize,
61-
});
66+
{} as Record<string, Link>,
67+
);
6268

6369
const response = domains.map((domain) => ({
6470
...transformDomain(domain),
6571
...(includeLink &&
66-
domain.links.length > 0 && {
72+
linkMap[domain.slug] && {
6773
link: transformLink({
68-
...domain.links[0],
69-
tags: domain.links[0]["tags"].map((tag) => tag),
74+
...linkMap[domain.slug],
75+
tags: linkMap[domain.slug]["tags"].map((tag) => tag),
7076
}),
7177
}),
7278
}));

apps/web/lib/api/domains/queue.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,20 @@ import { qstash } from "@/lib/cron";
22
import { APP_DOMAIN_WITH_NGROK } from "@dub/utils";
33

44
export async function queueDomainUpdate({
5-
workspaceId,
65
oldDomain,
76
newDomain,
8-
page,
97
delay,
108
}: {
11-
workspaceId: string;
129
oldDomain: string;
1310
newDomain: string;
14-
page: number;
1511
delay?: number;
1612
}) {
1713
return await qstash.publishJSON({
1814
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/domains/update`,
1915
...(delay && { delay }),
2016
body: {
21-
workspaceId,
2217
oldDomain,
2318
newDomain,
24-
page,
2519
},
2620
});
2721
}

apps/web/lib/api/links/cache.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,29 +75,6 @@ class LinkCache {
7575
return await pipeline.exec();
7676
}
7777

78-
async rename({
79-
links,
80-
oldDomain,
81-
}: {
82-
links: Pick<LinkProps, "domain" | "key">[];
83-
oldDomain: string;
84-
}) {
85-
if (links.length === 0) {
86-
return;
87-
}
88-
89-
const pipeline = redis.pipeline();
90-
91-
links.forEach(({ domain, key }) => {
92-
const oldCacheKey = this._createKey({ domain: oldDomain, key });
93-
const newCacheKey = this._createKey({ domain, key });
94-
95-
pipeline.renamenx(oldCacheKey, newCacheKey);
96-
});
97-
98-
return await pipeline.exec();
99-
}
100-
10178
async expireMany(links: Pick<LinkProps, "domain" | "key">[]) {
10279
if (links.length === 0) {
10380
return;

apps/web/scripts/fix-broken-root-domains.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @ts-nocheck
2+
13
import { createLink } from "@/lib/api/links";
24
import { prisma } from "@dub/prisma";
35
import { DEFAULT_LINK_PROPS } from "@dub/utils";

packages/prisma/schema/domain.prisma

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ model Domain {
1111
logo String?
1212
appleAppSiteAssociation Json?
1313
assetLinks Json?
14-
links Link[]
1514
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
1615
projectId String?
1716
registeredDomain RegisteredDomain?

packages/prisma/schema/link.prisma

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,11 @@ model Link {
4343
userId String?
4444
4545
// Project that the link belongs to
46-
project Project? @relation(fields: [projectId], references: [id], onUpdate: Cascade, onDelete: Cascade)
47-
projectId String?
48-
// Relational reference to the project domain
49-
projectDomain Domain? @relation(fields: [domain], references: [slug], onUpdate: Cascade, onDelete: Cascade)
46+
project Project? @relation(fields: [projectId], references: [id], onUpdate: Cascade, onDelete: Cascade)
47+
projectId String?
48+
5049
// Program that the link belongs to
51-
programId String?
50+
programId String?
5251
5352
folderId String?
5453
folder Folder? @relation(fields: [folderId], references: [id], onUpdate: Cascade, onDelete: SetNull)
@@ -84,9 +83,9 @@ model Link {
8483
commissions Commission[]
8584
8685
@@unique([domain, key])
86+
@@unique([projectId, externalId])
8787
@@index([projectId, url(length: 500)])
8888
@@index([projectId, folderId, archived, createdAt(sort: Desc)])
89-
@@unique([projectId, externalId])
9089
@@index([programId, partnerId])
9190
@@index(folderId) // used in /api/folders
9291
@@index(userId) // for relation to User table

0 commit comments

Comments
 (0)