Files
IBKRTrader/Core/Workers/BuiltIn/BackupWorker.cs
T
RichardandClaude Opus 4.8 ebeb035e92 Initial commit: IBKRTrader
.NET WinForms-Anwendung (Core, Modules/CongressTrading, UI).
Enthaelt .gitignore und settings.example.json als Konfigurationsvorlage.
Echte settings.json mit Zugangsdaten ist bewusst ausgeschlossen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 18:19:47 +02:00

147 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using IBKRTrader.Core.Database;
using IBKRTrader.Core.Logging;
using IBKRTrader.Core.Settings;
namespace IBKRTrader.Core.Workers.BuiltIn;
/// <summary>
/// BackupWorker (Core) läuft alle 30 Minuten (konfigurierbar).
/// 1. Ruft mysqldump.exe auf → SQL-Dump in Backups\DB\
/// 2. Kopiert Logs\ → Backups\Logs\
/// Falls mysqldump nicht gefunden: Warnung und Überspringen.
/// </summary>
public class BackupWorker : WorkerBase
{
private readonly SettingsService _settings;
public override string Name => "BackupWorker";
public override string Module => "Core";
public override WorkerType Type => WorkerType.Worker;
protected override TimeSpan? Interval =>
TimeSpan.FromMinutes(_settings.Settings.WorkerSettings.BackupWorker.IntervalMinutes);
public BackupWorker(LoggingService logger, DatabaseService db, SettingsService settings)
: base(logger, db)
{
_settings = settings;
Info.Active = settings.Settings.WorkerSettings.BackupWorker.Enabled;
}
protected override async Task ExecuteAsync(CancellationToken ct)
{
var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm");
var backupRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Backups");
var dbDir = Path.Combine(backupRoot, "DB");
var logsDir = Path.Combine(backupRoot, "Logs");
Directory.CreateDirectory(dbDir);
Directory.CreateDirectory(logsDir);
// ── 1. Datenbank-Dump ────────────────────────────────────────────────
await RunMysqlDumpAsync(dbDir, timestamp, ct);
// ── 2. Logs-Backup ───────────────────────────────────────────────────
CopyLogs(logsDir, timestamp);
Logger.Info(Module, $"Backup abgeschlossen: {timestamp}");
}
// ─── mysqldump ────────────────────────────────────────────────────────────
private async Task RunMysqlDumpAsync(string dbDir, string timestamp, CancellationToken ct)
{
var dump = FindMysqldump();
if (dump == null)
{
Logger.Warn(Module, "mysqldump.exe nicht gefunden DB-Backup übersprungen.");
return;
}
var db = _settings.Settings.Database;
var dumpFile = Path.Combine(dbDir, $"{db.Database}_{timestamp}.sql");
var args = $"--host={db.Host} --port={db.Port} " +
$"--user={db.User} --password={db.Password} " +
$"--single-transaction --routines --triggers " +
$"{db.Database} --result-file=\"{dumpFile}\"";
var psi = new System.Diagnostics.ProcessStartInfo
{
FileName = dump,
Arguments = args,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var proc = System.Diagnostics.Process.Start(psi)
?? throw new InvalidOperationException("mysqldump konnte nicht gestartet werden.");
await proc.WaitForExitAsync(ct);
if (proc.ExitCode != 0)
{
var err = await proc.StandardError.ReadToEndAsync(ct);
Logger.Warn(Module, $"mysqldump Exitcode {proc.ExitCode}: {err}");
}
else
{
Logger.Info(Module, $"DB-Dump erstellt: {Path.GetFileName(dumpFile)}");
}
}
private static string? FindMysqldump()
{
// Häufige Installationspfade auf Windows-Server
var candidates = new[]
{
"mysqldump.exe",
@"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe",
@"C:\Program Files\MySQL\MySQL Server 8.4\bin\mysqldump.exe",
@"C:\xampp\mysql\bin\mysqldump.exe"
};
foreach (var c in candidates)
if (File.Exists(c)) return c;
// PATH-Suche
var pathVar = Environment.GetEnvironmentVariable("PATH") ?? "";
foreach (var dir in pathVar.Split(';'))
{
var full = Path.Combine(dir.Trim(), "mysqldump.exe");
if (File.Exists(full)) return full;
}
return null;
}
// ─── Logs kopieren ────────────────────────────────────────────────────────
private void CopyLogs(string logsBackupDir, string timestamp)
{
try
{
var srcLogs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
if (!Directory.Exists(srcLogs)) return;
var destDir = Path.Combine(logsBackupDir, timestamp);
CopyDirectory(srcLogs, destDir);
Logger.Info(Module, $"Logs-Backup erstellt: {destDir}");
}
catch (Exception ex)
{
Logger.Warn(Module, $"Logs-Backup fehlgeschlagen: {ex.Message}");
}
}
private static void CopyDirectory(string src, string dest)
{
Directory.CreateDirectory(dest);
foreach (var file in Directory.GetFiles(src))
File.Copy(file, Path.Combine(dest, Path.GetFileName(file)), overwrite: true);
foreach (var dir in Directory.GetDirectories(src))
CopyDirectory(dir, Path.Combine(dest, Path.GetFileName(dir)));
}
}