Script-Check-Bug behoben: CheckDBScripts prüft jetzt alle registrierten Scripts, nicht nur das erste. Alle vier Check-Methoden sind auf das gleiche Muster umgestellt (Where auf Fehler filtern, Meldungen mit ; joinen), d.h. sie melden jetzt auch jeweils alle fehlenden Einträge ihrer Kategorie statt nur den ersten.

Alle Fehler sammeln: DoHealthCheckup bricht nicht mehr beim ersten Fehler ab, sondern sammelt die Meldungen aller Checkups und gibt sie zusammen in Message zurück.
Exception-Logging: Wirft ein Checkup eine Exception, wird sie jetzt vollständig per log4net geloggt (gleiches Idiom wie im WCFErrorHandler über LoggerUtils.GetLogger); nach außen geht weiterhin nur ex.Message.
Listen direkt initialisiert statt Lazy-Init — alle is null-Checks entfallen, die Add*-Methoden sind jetzt Einzeiler.
Naming auf PascalCase vereinheitlicht (AddWebConfigCheck, RegisterCheckup, CheckDBScripts, …) und ungenutzte Usings entfernt.
This commit is contained in:
2026-07-13 11:39:36 +02:00
parent cbf3599521
commit f6fef62bdd
5 changed files with 68 additions and 132 deletions

View File

@@ -1,8 +1,3 @@
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.AI;
using BeWo.Service.Attributes;
using BeWo.Service.Core;
using BeWo.Service.ServiceContracts.Enhanced;
using BeWo.Service.Status;
using BS.Shared;
@@ -10,14 +5,11 @@ using BS.Shared.Core;
using BS.Shared.DataContracts;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Service.ServiceImplementations.Enhanced
{
@@ -40,8 +32,14 @@ namespace BeWo.Service.ServiceImplementations.Enhanced
result.DatabaseOk = new DatenbankStatusService().DoHealthCheckup();
// Einzelne Subsysteme prüfen
result.Services.Add(new GeneralStatusService().DoHealthCheckup());
result.Services.Add(new AiStatusService().DoHealthCheckup());
var statusServices = new List<BaseStatusService>
{
new GeneralStatusService(),
new AiStatusService()
};
foreach (var service in statusServices)
result.Services.Add(service.DoHealthCheckup());
var allHealthy = result.DatabaseOk.IsOk && result.Services.All(x => x.IsOk);
if (!allHealthy)

View File

@@ -1,23 +1,16 @@
using BeWo.Service.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Service.Status
{
public class AiStatusService : BaseStatusService
{
public AiStatusService() : base("AI")
{
addWebConfigCheck(WebConfigSetting.OllamaUrl,
AddWebConfigCheck(WebConfigSetting.OllamaUrl,
WebConfigSetting.Ollama2Url,
WebConfigSetting.AiPromptsUrl);
addWebSecretConfigCheck(WebSecretConfigSetting.Ollama2Key);
AddWebSecretConfigCheck(WebSecretConfigSetting.Ollama2Key);
addDBScript("Changes_2026-05-22 AiConv ActionType",
AddDBScript("Changes_2026-05-22 AiConv ActionType",
"Changes_2026-06-03 AiRoutine RoutineType",
"Changes_2026-06-18 AiModel default updaten",
"Changes_2026-07-08 AiConversation Promptreferenz",

View File

@@ -1,165 +1,124 @@
using BeWo.Data.Access;
using BeWo.Data.Access;
using BeWo.ServerUtils.Core;
using BeWo.Service.Core;
using BS.Shared.DataContracts;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Service.Status
{
public class BaseStatusService
{
private static readonly log4net.ILog log = LoggerUtils.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected string Name { get; set; }
protected List<Func<string>> Checkups { get; set; }
protected List<Func<string>> Checkups { get; } = new List<Func<string>>();
private List<WebConfigSetting> RequiredWebConfigs { get; set; }
private List<WebSecretConfigSetting> RequiredWebSecretConfigs { get; set; }
private List<string> RequiredDBScripts { get; set; }
private List<SpecialConfig> RequiredConfigs { get; set; }
private List<WebConfigSetting> RequiredWebConfigs { get; } = new List<WebConfigSetting>();
private List<WebSecretConfigSetting> RequiredWebSecretConfigs { get; } = new List<WebSecretConfigSetting>();
private List<string> RequiredDBScripts { get; } = new List<string>();
private List<SpecialConfig> RequiredConfigs { get; } = new List<SpecialConfig>();
public BaseStatusService(string name)
{
Name = name;
registerCheckup(checkWebConfig,
checkWebSecretConfig,
checkDBScripts,
checkConfig);
RegisterCheckup(CheckWebConfig,
CheckWebSecretConfig,
CheckDBScripts,
CheckConfig);
}
protected void addWebConfigCheck(params WebConfigSetting[] args)
protected void AddWebConfigCheck(params WebConfigSetting[] args)
{
if(RequiredWebConfigs is null)
RequiredWebConfigs = new List<WebConfigSetting>();
RequiredWebConfigs.AddRange(args);
}
protected void addWebSecretConfigCheck(params WebSecretConfigSetting[] args)
{
if(RequiredWebSecretConfigs is null)
RequiredWebSecretConfigs = new List<WebSecretConfigSetting>();
protected void AddWebSecretConfigCheck(params WebSecretConfigSetting[] args)
{
RequiredWebSecretConfigs.AddRange(args);
}
protected void addDBScript(params string[] args)
protected void AddDBScript(params string[] args)
{
if(RequiredDBScripts is null)
RequiredDBScripts = new List<string>();
RequiredDBScripts.AddRange(args);
}
protected void addCustomConfig(params SpecialConfig[] args)
{
if(RequiredConfigs is null)
RequiredConfigs = new List<SpecialConfig>();
protected void AddCustomConfig(params SpecialConfig[] args)
{
RequiredConfigs.AddRange(args);
}
protected void registerCheckup(params Func<string>[] args)
protected void RegisterCheckup(params Func<string>[] args)
{
if (Checkups is null)
Checkups = new List<Func<string>>();
Checkups.AddRange(args);
}
public ServiceStatusDC DoHealthCheckup()
{
string error = string.Empty;
bool ok = true;
var errors = new List<string>();
foreach (var func in Checkups)
{
try
{
error = func();
var error = func();
if (!string.IsNullOrEmpty(error))
errors.Add(error);
}
catch(Exception ex)
catch (Exception ex)
{
error = ex.Message;
log.Error($"Health-Checkup '{Name}' fehlgeschlagen", ex);
errors.Add(ex.Message);
}
ok = string.IsNullOrEmpty(error);
if (!ok)
break;
}
return new ServiceStatusDC
{
Name = Name,
IsOk = ok,
Message = ok ? "OK" : error
IsOk = errors.Count == 0,
Message = errors.Count == 0 ? "OK" : string.Join("; ", errors)
};
}
private string checkWebConfig()
private string CheckWebConfig()
{
if (RequiredWebConfigs is null)
return null;
var missing = RequiredWebConfigs
.Where(x => string.IsNullOrWhiteSpace(MergedConfig.GetSetting(x)))
.Select(x => $"'{x}' wurde nicht korrekt konfiguriert");
foreach (var webConfig in RequiredWebConfigs)
{
var url = MergedConfig.GetSetting(webConfig);
if (string.IsNullOrWhiteSpace(url))
return $"'{webConfig}' wurde nicht korrekt konfiguriert";
}
return null;
return string.Join("; ", missing);
}
private string checkWebSecretConfig()
private string CheckWebSecretConfig()
{
if (RequiredWebSecretConfigs is null)
return null;
var missing = RequiredWebSecretConfigs
.Where(x => string.IsNullOrWhiteSpace(MergedConfig.GetSecretSetting(x)))
.Select(x => $"'{x}' wurde nicht korrekt konfiguriert");
foreach (var webSecretConfig in RequiredWebSecretConfigs)
{
var key = MergedConfig.GetSecretSetting(webSecretConfig);
if (string.IsNullOrWhiteSpace(key))
return $"'{webSecretConfig}' wurde nicht korrekt konfiguriert";
}
return null;
}
private string checkDBScripts()
{
if (RequiredDBScripts is null)
return null;
foreach (var script in RequiredDBScripts)
{
var executed = DAOFactory.ScriptDAO.IsScriptExecuted(script);
return executed ? null : $"Script '{script}' wurde nicht ausgeführt";
}
return null;
return string.Join("; ", missing);
}
private string checkConfig()
private string CheckDBScripts()
{
if (RequiredConfigs is null)
return null;
var missing = RequiredDBScripts
.Where(x => !DAOFactory.ScriptDAO.IsScriptExecuted(x))
.Select(x => $"Script '{x}' wurde nicht ausgeführt");
foreach (var config in RequiredConfigs)
{
var configPath = ConfigReader.GetConfigPath(config);
return string.Join("; ", missing);
}
if (!File.Exists(configPath))
return $"SpecialConfig.{config} wurde nicht korrekt konfiguriert";
}
private string CheckConfig()
{
var missing = RequiredConfigs
.Where(x => !File.Exists(ConfigReader.GetConfigPath(x)))
.Select(x => $"SpecialConfig.{x} wurde nicht korrekt konfiguriert");
return null;
return string.Join("; ", missing);
}
}
}

View File

@@ -1,10 +1,5 @@
using BeWo.Data.Access;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Service.Status
{
@@ -12,13 +7,13 @@ namespace BeWo.Service.Status
{
public DatenbankStatusService() : base("Datenbank")
{
registerCheckup(CheckDatenbank);
RegisterCheckup(CheckDatenbank);
}
private string CheckDatenbank()
{
// Leichter DB-Ping z.B. eine einfache Abfrage über DAOFactory
DAOFactory.GenericDAO.GetAll<ApplicationUser>();
// Leichter DB-Ping COUNT-Abfrage statt Laden aller Datensätze
DAOFactory.GenericDAO.Any<ApplicationUser>();
return null;
}

View File

@@ -1,19 +1,10 @@
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BS.Shared.DataContracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Service.Status
{
public class GeneralStatusService : BaseStatusService
{
public GeneralStatusService() : base("Allgemein")
{
addWebSecretConfigCheck(WebSecretConfigSetting.AppStatusApiKey);
AddWebSecretConfigCheck(WebSecretConfigSetting.AppStatusApiKey);
}
}
}