fix(worker): Base-URL ohne Schema laesst die Ticket-Anbindung scheitern

Ein blanker Hostname ist eine relative URI; HttpClient lehnt sie mit
InvalidOperationException ab. Die lief an dem zu engen catch-Filter
vorbei, flog roh aus dem Hub und wurde von TryInvokeAsync zu null
verschluckt - die UI meldete "Worker not reachable", obwohl der Worker
lief und die Ursache eine Eingabe war.

- TicketSystemConfig ergaenzt fehlendes http://
- BandelTicketClient uebersetzt jede Transport-Exception in eine
  lesbare TicketApiException
- TestTicketConnection faengt alles und antwortet mit dem Grund
- GetTicketSettings liefert die effektive URL, damit die Ergaenzung
  sichtbar ist
This commit is contained in:
mika kuns
2026-08-27 14:03:52 +02:00
parent 2fe2ac83b1
commit 3322152b9c
6 changed files with 95 additions and 8 deletions
@@ -64,7 +64,12 @@ public sealed class BandelTicketClient
{
response = await _http.SendAsync(request, ct);
}
catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException && !ct.IsCancellationRequested)
// Bewusst JEDE Exception, nicht nur HttpRequestException/TaskCanceledException: eine
// fehlerhafte Base-URL wirft InvalidOperationException oder UriFormatException, und die
// flogen vorher roh aus dem Hub. Der Aufrufer bekam dadurch statt eines Grundes nur ein
// verschlucktes null — die UI meldete "Worker not reachable", obwohl der Worker lief.
// Eine echte Abbruchanforderung wird davon nicht angefasst.
catch (Exception ex) when (!ct.IsCancellationRequested)
{
throw new TicketApiException($"Ticketsystem nicht erreichbar ({_baseUrl}): {ex.Message}");
}
@@ -25,9 +25,25 @@ public sealed class TicketSystemConfig
_pat = pat;
}
public string? BaseUrl => string.IsNullOrWhiteSpace(_worker.TicketApiBaseUrl)
? null
: _worker.TicketApiBaseUrl.Trim().TrimEnd('/');
/// <summary>
/// Die Base-URL, wie HttpClient sie braucht: absolut, ohne Schrägstrich am Ende.
///
/// Ein Feld namens "API base URL" lädt dazu ein, einen blanken Hostnamen einzutippen.
/// Ohne Schema ist das aber eine RELATIVE URI, und HttpClient lehnt sie mit einer
/// InvalidOperationException ab, lange bevor ein Paket fließt. Deshalb wird hier — und nur
/// hier, weil das der einzige Leser ist — `http://` ergänzt. `http` und nicht `https`, weil
/// die API im Intranet ohne TLS läuft; wer TLS will, tippt das Schema hin und es bleibt stehen.
/// </summary>
public string? BaseUrl
{
get
{
var raw = _worker.TicketApiBaseUrl?.Trim();
if (string.IsNullOrEmpty(raw)) return null;
if (!raw.Contains("://", StringComparison.Ordinal)) raw = "http://" + raw;
return raw.TrimEnd('/');
}
}
public string? Token => _pat.Store.Read();