mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
fix(templates): add fetch timeout and handle network errors gracefully
Add 10s AbortSignal timeout to all template fetch calls so they fail cleanly instead of hanging indefinitely when templates.dokploy.com is unreachable. Add try/catch to getTags endpoint which was missing error handling, causing a 500 instead of returning an empty list. Closes #4282
This commit is contained in:
@@ -700,11 +700,14 @@ export const composeRouter = createTRPCRouter({
|
||||
getTags: protectedProcedure
|
||||
.input(z.object({ baseUrl: z.string().optional() }))
|
||||
.query(async ({ input }) => {
|
||||
const githubTemplates = await fetchTemplatesList(input.baseUrl);
|
||||
|
||||
const allTags = githubTemplates.flatMap((template) => template.tags);
|
||||
const uniqueTags = _.uniq(allTags);
|
||||
return uniqueTags;
|
||||
try {
|
||||
const githubTemplates = await fetchTemplatesList(input.baseUrl);
|
||||
const allTags = githubTemplates.flatMap((template) => template.tags);
|
||||
return _.uniq(allTags);
|
||||
} catch (error) {
|
||||
console.warn("Failed to fetch template tags:", error);
|
||||
return [];
|
||||
}
|
||||
}),
|
||||
disconnectGitProvider: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
|
||||
@@ -55,25 +55,22 @@ interface TemplateMetadata {
|
||||
export async function fetchTemplatesList(
|
||||
baseUrl = "https://templates.dokploy.com",
|
||||
): Promise<TemplateMetadata[]> {
|
||||
try {
|
||||
const response = await fetch(`${baseUrl}/meta.json`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
||||
}
|
||||
const templates = (await response.json()) as TemplateMetadata[];
|
||||
return templates.map((template) => ({
|
||||
id: template.id,
|
||||
name: template.name,
|
||||
description: template.description,
|
||||
version: template.version,
|
||||
logo: template.logo,
|
||||
links: template.links,
|
||||
tags: template.tags,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("Error fetching templates list:", error);
|
||||
throw error;
|
||||
const response = await fetch(`${baseUrl}/meta.json`, {
|
||||
signal: AbortSignal.timeout(10000),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
||||
}
|
||||
const templates = (await response.json()) as TemplateMetadata[];
|
||||
return templates.map((template) => ({
|
||||
id: template.id,
|
||||
name: template.name,
|
||||
description: template.description,
|
||||
version: template.version,
|
||||
logo: template.logo,
|
||||
links: template.links,
|
||||
tags: template.tags,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,27 +80,26 @@ export async function fetchTemplateFiles(
|
||||
templateId: string,
|
||||
baseUrl = "https://templates.dokploy.com",
|
||||
): Promise<{ config: CompleteTemplate; dockerCompose: string }> {
|
||||
try {
|
||||
// Fetch both files in parallel
|
||||
const [templateYmlResponse, dockerComposeResponse] = await Promise.all([
|
||||
fetch(`${baseUrl}/blueprints/${templateId}/template.toml`),
|
||||
fetch(`${baseUrl}/blueprints/${templateId}/docker-compose.yml`),
|
||||
]);
|
||||
const timeout = AbortSignal.timeout(10000);
|
||||
const [templateYmlResponse, dockerComposeResponse] = await Promise.all([
|
||||
fetch(`${baseUrl}/blueprints/${templateId}/template.toml`, {
|
||||
signal: timeout,
|
||||
}),
|
||||
fetch(`${baseUrl}/blueprints/${templateId}/docker-compose.yml`, {
|
||||
signal: timeout,
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!templateYmlResponse.ok || !dockerComposeResponse.ok) {
|
||||
throw new Error("Template files not found");
|
||||
}
|
||||
|
||||
const [templateYml, dockerCompose] = await Promise.all([
|
||||
templateYmlResponse.text(),
|
||||
dockerComposeResponse.text(),
|
||||
]);
|
||||
|
||||
const config = parse(templateYml) as CompleteTemplate;
|
||||
|
||||
return { config, dockerCompose };
|
||||
} catch (error) {
|
||||
console.error(`Error fetching template ${templateId}:`, error);
|
||||
throw error;
|
||||
if (!templateYmlResponse.ok || !dockerComposeResponse.ok) {
|
||||
throw new Error("Template files not found");
|
||||
}
|
||||
|
||||
const [templateYml, dockerCompose] = await Promise.all([
|
||||
templateYmlResponse.text(),
|
||||
dockerComposeResponse.text(),
|
||||
]);
|
||||
|
||||
const config = parse(templateYml) as CompleteTemplate;
|
||||
|
||||
return { config, dockerCompose };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user