feat: add job on start option for icons updater (#442)

This commit is contained in:
Meier Lukas
2024-05-05 22:20:38 +02:00
committed by GitHub
parent 4b80b16b53
commit 7b31684c84
2 changed files with 79 additions and 70 deletions

View File

@@ -8,83 +8,81 @@ import { logger } from "@homarr/log";
import { EVERY_WEEK } from "~/lib/cron-job/constants";
import { createCronJob } from "~/lib/cron-job/creator";
export const iconsUpdaterJob = createCronJob(EVERY_WEEK).withCallback(
async () => {
logger.info(`Updating icon repository cache...`);
const stopWatch = new Stopwatch();
const repositoryIconGroups = await fetchIconsAsync();
const countIcons = repositoryIconGroups
.map((group) => group.icons.length)
.reduce((partialSum, arrayLength) => partialSum + arrayLength, 0);
logger.info(
`Successfully fetched ${countIcons} icons from ${repositoryIconGroups.length} repositories within ${stopWatch.getElapsedInHumanWords()}`,
);
export const iconsUpdaterJob = createCronJob(EVERY_WEEK, {
runOnStart: true,
}).withCallback(async () => {
logger.info("Updating icon repository cache...");
const stopWatch = new Stopwatch();
const repositoryIconGroups = await fetchIconsAsync();
const countIcons = repositoryIconGroups
.map((group) => group.icons.length)
.reduce((partialSum, arrayLength) => partialSum + arrayLength, 0);
logger.info(
`Successfully fetched ${countIcons} icons from ${repositoryIconGroups.length} repositories within ${stopWatch.getElapsedInHumanWords()}`,
);
const databaseIconGroups = await db.query.iconRepositories.findMany({
with: {
icons: true,
},
});
const databaseIconGroups = await db.query.iconRepositories.findMany({
with: {
icons: true,
},
});
const skippedChecksums: string[] = [];
let countDeleted = 0;
let countInserted = 0;
const skippedChecksums: string[] = [];
let countDeleted = 0;
let countInserted = 0;
logger.info(`Updating icons in database...`);
stopWatch.reset();
logger.info("Updating icons in database...");
stopWatch.reset();
await db.transaction(async (transaction) => {
for (const repositoryIconGroup of repositoryIconGroups) {
if (!repositoryIconGroup.success) {
await db.transaction(async (transaction) => {
for (const repositoryIconGroup of repositoryIconGroups) {
if (!repositoryIconGroup.success) {
continue;
}
const repositoryInDb = databaseIconGroups.find(
(dbIconGroup) => dbIconGroup.slug === repositoryIconGroup.slug,
);
const repositoryIconGroupId: string = repositoryInDb?.id ?? createId();
if (!repositoryInDb?.id) {
await transaction.insert(iconRepositories).values({
id: repositoryIconGroupId,
slug: repositoryIconGroup.slug,
});
}
for (const icon of repositoryIconGroup.icons) {
if (
databaseIconGroups
.flatMap((group) => group.icons)
.some((dbIcon) => dbIcon.checksum === icon.checksum)
) {
skippedChecksums.push(icon.checksum);
continue;
}
const repositoryInDb = databaseIconGroups.find(
(dbIconGroup) => dbIconGroup.slug === repositoryIconGroup.slug,
);
const repositoryIconGroupId: string = repositoryInDb?.id ?? createId();
if (!repositoryInDb?.id) {
await transaction.insert(iconRepositories).values({
id: repositoryIconGroupId,
slug: repositoryIconGroup.slug,
});
}
for (const icon of repositoryIconGroup.icons) {
if (
databaseIconGroups
.flatMap((group) => group.icons)
.some((dbIcon) => dbIcon.checksum == icon.checksum)
) {
skippedChecksums.push(icon.checksum);
continue;
}
await transaction.insert(icons).values({
id: createId(),
checksum: icon.checksum,
name: icon.fileNameWithExtension,
url: icon.imageUrl.href,
iconRepositoryId: repositoryIconGroupId,
});
countInserted++;
}
await transaction.insert(icons).values({
id: createId(),
checksum: icon.checksum,
name: icon.fileNameWithExtension,
url: icon.imageUrl.href,
iconRepositoryId: repositoryIconGroupId,
});
countInserted++;
}
}
const deadIcons = databaseIconGroups
.flatMap((group) => group.icons)
.filter((icon) => !skippedChecksums.includes(icon.checksum));
const deadIcons = databaseIconGroups
.flatMap((group) => group.icons)
.filter((icon) => !skippedChecksums.includes(icon.checksum));
for (const icon of deadIcons) {
await transaction
.delete(icons)
.where(eq(icons.checksum, icon.checksum));
countDeleted++;
}
});
for (const icon of deadIcons) {
await transaction.delete(icons).where(eq(icons.checksum, icon.checksum));
countDeleted++;
}
});
logger.info(
`Updated database within ${stopWatch.getElapsedInHumanWords()} (-${countDeleted}, +${countInserted})`,
);
},
);
logger.info(
`Updated database within ${stopWatch.getElapsedInHumanWords()} (-${countDeleted}, +${countInserted})`,
);
});

View File

@@ -2,9 +2,20 @@ import cron from "node-cron";
import type { MaybePromise } from "@homarr/common/types";
export const createCronJob = (cronExpression: string) => {
interface CreateCronJobOptions {
runOnStart?: boolean;
}
export const createCronJob = (
cronExpression: string,
options: CreateCronJobOptions = { runOnStart: false },
) => {
return {
withCallback: (callback: () => MaybePromise<void>) => {
if (options.runOnStart) {
void callback();
}
const task = cron.schedule(cronExpression, () => void callback(), {
scheduled: false,
});