Parallelize invoice image fetch, add telemetry, generalize HtmlConverter
- InvoiceService.ResolveInlineImagesAsync now fetches an invoice's distinct whitelisted images concurrently (SemaphoreSlim-capped at 4) instead of one at a time. It ran inline on every invoice render, including repeated draft-preview renders, so N sequential mfr-portal round-trips could otherwise add N x latency to a user-facing request. - Add fuchs.invoice.inlineimages.fetches (counter, tagged by outcome: success/http_error/bad_content_type/oversized/exception) and fuchs.invoice.inlineimages.resolve.duration (histogram) to FuchsTelemetry, matching the project's observability convention for outbound-HTTP operations. - MigraDocExtensions.HtmlConverter's pre-resolved-image parameter is renamed inlineImages -> resolvedImages with generic docs: the converter fetches nothing and knows nothing about invoices — which images to resolve, and any whitelist/network policy, is entirely the caller's concern (InvoiceService, ADR 0018 today; any future caller tomorrow). - Add tests asserting fetches actually overlap (not just faster) and that the new counter/histogram are recorded. - Update ADR 0018 to describe the concurrent fetch, telemetry, and the generalized converter parameter. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,9 @@ public static class FuchsTelemetry
|
||||
public static readonly Counter<long> SystemProbes =
|
||||
Meter.CreateCounter<long>("fuchs.systemstatus.probes", "{probe}",
|
||||
"Admin system-status connectivity probes executed, tagged by component and outcome.");
|
||||
public static readonly Counter<long> InvoiceInlineImageFetches =
|
||||
Meter.CreateCounter<long>("fuchs.invoice.inlineimages.fetches", "{fetch}",
|
||||
"Invoice-text image fetches for inline PDF rendering (ADR 0018), tagged by outcome.");
|
||||
|
||||
// ── Performance histograms (durations in milliseconds) ───────────────────
|
||||
public static readonly Histogram<double> PdfRenderDuration =
|
||||
@@ -62,6 +65,9 @@ public static class FuchsTelemetry
|
||||
Meter.CreateHistogram<double>("fuchs.report.render.duration", "ms", "Report render duration.");
|
||||
public static readonly Histogram<double> EmailSendDuration =
|
||||
Meter.CreateHistogram<double>("fuchs.email.send.duration", "ms", "Email send round-trip duration.");
|
||||
public static readonly Histogram<double> InvoiceInlineImagesResolveDuration =
|
||||
Meter.CreateHistogram<double>("fuchs.invoice.inlineimages.resolve.duration", "ms",
|
||||
"Total wall-clock time to fetch an invoice's inline images (all images in parallel).");
|
||||
|
||||
/// <summary>Starts a span on the application's <see cref="ActivitySource"/>.</summary>
|
||||
public static Activity? StartActivity(string name, ActivityKind kind = ActivityKind.Internal) =>
|
||||
|
||||
Reference in New Issue
Block a user