fix: resilient RSS/releases fetching and effect deps
- RSS feed: Promise.allSettled so one bad URL doesn't fail all feeds - Releases: Promise.allSettled so one bad repo doesn't blank widget - system-resources: add data to useEffect deps - media-requests: invalidate all mediaRequests queries on answer
This commit is contained in:
4 files changed
+22
-6
No files matched your search
@@ -1,12 +1,15 @@
|
||||
import { escapeForRegEx } from "@tiptap/react";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createLogger } from "@homarr/core/infrastructure/logs";
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import { releasesRequestHandler } from "@homarr/request-handler/releases";
|
||||
|
||||
import { createOneIntegrationMiddleware } from "../../middlewares/integration";
|
||||
import { createTRPCRouter, publicProcedure } from "../../trpc";
|
||||
|
||||
const logger = createLogger({ module: "releases" });
|
||||
|
||||
const formatVersionFilterRegex = (versionFilter: z.infer<typeof releaseVersionFilterSchema> | undefined) => {
|
||||
if (!versionFilter) return undefined;
|
||||
|
||||
@@ -38,7 +41,7 @@ export const releasesRouter = createTRPCRouter({
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
return await Promise.all(
|
||||
const settled = await Promise.allSettled(
|
||||
input.repositories.map(async (repository) => {
|
||||
const response = await releasesRequestHandler
|
||||
.handler(ctx.integration, {
|
||||
@@ -56,5 +59,11 @@ export const releasesRouter = createTRPCRouter({
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return settled.flatMap((result, index) => {
|
||||
if (result.status === "fulfilled") return [result.value];
|
||||
logger.warn("Release fetch failed", { repository: input.repositories[index]?.identifier, error: result.reason });
|
||||
return [];
|
||||
});
|
||||
}),
|
||||
});
|
||||
@@ -5,11 +5,14 @@ import type { Session } from "@homarr/auth";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { eq } from "@homarr/db";
|
||||
import { items, users } from "@homarr/db/schema";
|
||||
import { createLogger } from "@homarr/core/infrastructure/logs";
|
||||
import { rssFeedsRequestHandler } from "@homarr/request-handler/rss-feeds";
|
||||
|
||||
import type { WidgetComponentProps } from "../../../../widgets/src";
|
||||
import { createTRPCRouter, publicProcedure } from "../../trpc";
|
||||
|
||||
const logger = createLogger({ module: "rssFeed" });
|
||||
|
||||
const feedsInput = z.object({
|
||||
urls: z.array(z.string()).max(100),
|
||||
maximumAmountPosts: z.number(),
|
||||
@@ -21,7 +24,7 @@ export const rssFeedRouter = createTRPCRouter({
|
||||
? input.urls
|
||||
: await restrictUrlsAsync(ctx.db, input.urls);
|
||||
|
||||
const rssFeeds = await Promise.all(
|
||||
const settled = await Promise.allSettled(
|
||||
urls.map(async (url) => {
|
||||
const innerHandler = rssFeedsRequestHandler.handler({
|
||||
url,
|
||||
@@ -31,8 +34,12 @@ export const rssFeedRouter = createTRPCRouter({
|
||||
}),
|
||||
);
|
||||
|
||||
return rssFeeds
|
||||
.flatMap((rssFeed) => rssFeed.data.entries)
|
||||
return settled
|
||||
.flatMap((result, index) => {
|
||||
if (result.status === "fulfilled") return result.value.data.entries;
|
||||
logger.warn("RSS feed fetch failed", { url: urls[index], error: result.reason });
|
||||
return [];
|
||||
})
|
||||
.slice(0, input.maximumAmountPosts)
|
||||
.toSorted((entryA, entryB) => {
|
||||
return entryA.published && entryB.published
|
||||
|
||||
@@ -200,7 +200,7 @@ interface DecisionButtonsProps {
|
||||
const DecisionButtons = ({ requestId, integrationId }: DecisionButtonsProps) => {
|
||||
const utils = clientApi.useUtils();
|
||||
const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation({
|
||||
onSettled: () => void utils.widget.mediaRequests.getLatestRequests.invalidate(),
|
||||
onSettled: () => void utils.widget.mediaRequests.invalidate(),
|
||||
});
|
||||
const t = useScopedI18n("widget.mediaRequests-requestList");
|
||||
const handleDecision = (answer: RouterInputs["widget"]["mediaRequests"]["answerRequest"]["answer"]) => {
|
||||
|
||||
@@ -50,7 +50,7 @@ export default function SystemResources({ integrationIds, options }: WidgetCompo
|
||||
const firstItem = data[0];
|
||||
if (!firstItem) return;
|
||||
setItems((prev) => [...prev, toChartItem(firstItem.healthInfo)].slice(-MAX_QUEUE_SIZE));
|
||||
}, [dataUpdatedAt]);
|
||||
}, [dataUpdatedAt, data]);
|
||||
|
||||
const showNetwork =
|
||||
items.length === 0 || (items.every((item) => item.network !== null) && options.visibleCharts.includes("network"));
|
||||
|
||||
Reference in new issue
Block a user