Skip to content

Commit 04ac6c1

Browse files
committed
Fix various issues
1 parent e71e3ba commit 04ac6c1

File tree

6 files changed

+66
-13
lines changed

6 files changed

+66
-13
lines changed

docs/_docset.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ toc:
8686
- file: code.md
8787
- file: comments.md
8888
- file: conditionals.md
89-
- hidden: diagrams.md
89+
- file: diagrams.md
9090
- file: dropdowns.md
9191
- file: definition-lists.md
9292
- file: example_blocks.md

docs/syntax/diagrams.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ sequenceDiagram
8484
:::::{tab-item} Rendered
8585
::::{diagram} mermaid
8686
sequenceDiagram
87-
participant A as Alice
87+
participant A as Ada
8888
participant B as Bob
8989
A->>B: Hello Bob, how are you?
9090
B-->>A: Great!

src/Elastic.Markdown/Myst/Directives/Diagram/DiagramBlock.cs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ public override void FinalizeAndValidate(ParserContext context)
7171
// Register diagram for tracking and cleanup
7272
DiagramRegistry.RegisterDiagram(LocalSvgPath);
7373

74-
// Cache diagram asynchronously
74+
// Cache diagram asynchronously - fire and forget
75+
// Use simplified approach without lock files to avoid orphaned locks
7576
_ = Task.Run(() => TryCacheDiagramAsync(context));
7677
}
7778

@@ -125,7 +126,7 @@ private async Task TryCacheDiagramAsync(ParserContext context)
125126
var outputDirectory = context.Build.DocumentationOutputDirectory.FullName;
126127
var fullPath = Path.Combine(outputDirectory, LocalSvgPath);
127128

128-
// Skip if file already exists
129+
// Skip if file already exists - simple check without locking
129130
if (File.Exists(fullPath))
130131
return;
131132

@@ -136,17 +137,41 @@ private async Task TryCacheDiagramAsync(ParserContext context)
136137
_ = Directory.CreateDirectory(directory);
137138
}
138139

139-
// Download SVG from Kroki
140-
using var httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
141-
var svgContent = await httpClient.GetStringAsync(EncodedUrl);
140+
// Download SVG from Kroki using shared HttpClient
141+
var svgContent = await DiagramHttpClient.Instance.GetStringAsync(EncodedUrl);
142142

143-
// Write to local file
144-
await File.WriteAllTextAsync(fullPath, svgContent);
143+
// Basic validation - ensure we got SVG content
144+
// SVG can start with XML declaration, DOCTYPE, or directly with <svg>
145+
if (string.IsNullOrWhiteSpace(svgContent) || !svgContent.Contains("<svg", StringComparison.OrdinalIgnoreCase))
146+
{
147+
// Invalid content - don't cache
148+
return;
149+
}
150+
151+
// Write to local file atomically using a temp file
152+
var tempPath = fullPath + ".tmp";
153+
await File.WriteAllTextAsync(tempPath, svgContent);
154+
File.Move(tempPath, fullPath);
155+
}
156+
catch (HttpRequestException)
157+
{
158+
// Network-related failures - silent fallback to Kroki URLs
159+
// Caching is opportunistic, network issues shouldn't generate warnings
160+
}
161+
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
162+
{
163+
// Timeout - silent fallback to Kroki URLs
164+
// Timeouts are expected in slow network conditions
165+
}
166+
catch (IOException)
167+
{
168+
// File system issues - silent fallback to Kroki URLs
169+
// Disk space or permission issues shouldn't break builds
145170
}
146-
catch
171+
catch (Exception)
147172
{
148-
// Silent failure - caching is opportunistic
149-
// The system will fall back to Kroki URLs
173+
// Unexpected errors - silent fallback to Kroki URLs
174+
// Caching is opportunistic, any failure should fallback gracefully
150175
}
151176
}
152177
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
namespace Elastic.Markdown.Myst.Directives.Diagram;
6+
7+
/// <summary>
8+
/// Shared HttpClient for diagram downloads to avoid resource exhaustion
9+
/// </summary>
10+
public static class DiagramHttpClient
11+
{
12+
private static readonly Lazy<HttpClient> LazyHttpClient = new(() => new HttpClient
13+
{
14+
Timeout = TimeSpan.FromSeconds(30)
15+
});
16+
17+
/// <summary>
18+
/// Shared HttpClient instance for diagram downloads
19+
/// </summary>
20+
public static HttpClient Instance => LazyHttpClient.Value;
21+
}

src/Elastic.Markdown/Myst/Directives/Diagram/DiagramView.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<div class="diagram" data-diagram-type="@diagram.DiagramType">
77
@if (!string.IsNullOrEmpty(diagram.LocalSvgPath))
88
{
9-
<img src="@diagram.LocalSvgPath"
9+
<img src="/@diagram.LocalSvgPath"
1010
alt="@diagram.DiagramType diagram"
1111
loading="lazy"
1212
onerror="this.src='@diagram.EncodedUrl'" />

src/tooling/docs-builder/Http/DocumentationWebHost.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using Microsoft.AspNetCore.Hosting;
1919
using Microsoft.AspNetCore.Http;
2020
using Microsoft.Extensions.DependencyInjection;
21+
using Microsoft.Extensions.FileProviders;
2122
using Microsoft.Extensions.Hosting;
2223
using Microsoft.Extensions.Logging;
2324
using Westwind.AspNetCore.LiveReload;
@@ -152,6 +153,12 @@ await context.Response.WriteAsync(@"
152153
FileProvider = new EmbeddedOrPhysicalFileProvider(Context),
153154
RequestPath = "/_static"
154155
})
156+
.UseStaticFiles(
157+
new StaticFileOptions
158+
{
159+
FileProvider = new PhysicalFileProvider(Context.DocumentationOutputDirectory.FullName),
160+
RequestPath = ""
161+
})
155162
.UseRouting();
156163

157164
_ = _webApplication.MapGet("/", (ReloadableGeneratorState holder, Cancel ctx) =>

0 commit comments

Comments
 (0)