1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
import { count, eq } from "drizzle-orm";
import { z } from "zod";
import { bookmarkLinks, bookmarks, users } from "@hoarder/db/schema";
import {
LinkCrawlerQueue,
OpenAIQueue,
SearchIndexingQueue,
} from "@hoarder/shared/queues";
import { adminProcedure, router } from "../index";
export const adminAppRouter = router({
stats: adminProcedure
.output(
z.object({
numUsers: z.number(),
numBookmarks: z.number(),
pendingCrawls: z.number(),
failedCrawls: z.number(),
pendingIndexing: z.number(),
failedIndexing: z.number(),
pendingOpenai: z.number(),
failedOpenai: z.number(),
}),
)
.query(async ({ ctx }) => {
const [
[{ value: numUsers }],
[{ value: numBookmarks }],
[{ value: pendingCrawls }],
[{ value: failedCrawls }],
pendingIndexing,
failedIndexing,
pendingOpenai,
failedOpenai,
] = await Promise.all([
ctx.db.select({ value: count() }).from(users),
ctx.db.select({ value: count() }).from(bookmarks),
ctx.db
.select({ value: count() })
.from(bookmarkLinks)
.where(eq(bookmarkLinks.crawlStatus, "pending")),
ctx.db
.select({ value: count() })
.from(bookmarkLinks)
.where(eq(bookmarkLinks.crawlStatus, "failure")),
SearchIndexingQueue.getWaitingCount(),
SearchIndexingQueue.getFailedCount(),
OpenAIQueue.getWaitingCount(),
OpenAIQueue.getFailedCount(),
]);
return {
numUsers,
numBookmarks,
pendingCrawls,
failedCrawls,
pendingIndexing,
failedIndexing,
pendingOpenai,
failedOpenai,
};
}),
recrawlLinks: adminProcedure
.input(
z.object({
crawlStatus: z.enum(["success", "failure", "all"]),
}),
)
.mutation(async ({ ctx, input }) => {
const bookmarkIds = await ctx.db.query.bookmarkLinks.findMany({
columns: {
id: true,
},
...(input.crawlStatus === "all"
? {}
: { where: eq(bookmarkLinks.crawlStatus, input.crawlStatus) }),
});
await Promise.all(
bookmarkIds.map((b) =>
LinkCrawlerQueue.add("crawl", {
bookmarkId: b.id,
}),
),
);
}),
reindexAllBookmarks: adminProcedure.mutation(async ({ ctx }) => {
const bookmarkIds = await ctx.db.query.bookmarks.findMany({
columns: {
id: true,
},
});
await Promise.all(
bookmarkIds.map((b) =>
SearchIndexingQueue.add("search_indexing", {
bookmarkId: b.id,
type: "index",
}),
),
);
}),
});
|