@
R4: Worker von WorkerEngine auf IHostedService (Generic Host) - WorkerBase implementiert IHostedService (StartAsync/StopAsync mit CancellationToken, eigener CTS, Guard auf Info.Active); IWorker auf Metadaten + TriggerAsync reduziert - Worker via AddHostedService registriert (Core + Modul); AppHost.Start() startet sie, AppHost.StopAsync() stoppt sie - WorkerEngine auf leichte Registry reduziert (WorkerInfos fuer UI + TriggerWorkerAsync) - LauncherForm startet/stoppt keine Worker mehr (Host-getrieben) - Hosting.Abstractions im Core; Tests angepasst -> 43/43 gruen; smoke-ui + App-Start ok Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
This commit is contained in:
@@ -5,92 +5,31 @@ using IBKRTrader.Core.Logging;
|
||||
namespace IBKRTrader.Core.Workers;
|
||||
|
||||
/// <summary>
|
||||
/// Orchestriert alle registrierten IWorker.
|
||||
/// – Startet/stoppt Worker
|
||||
/// – Stellt BindingList für DataGridView bereit
|
||||
/// – Thread-sicher via ConcurrentDictionary
|
||||
/// Leichtgewichtige Registry über alle Worker/Services. Start/Stop übernimmt der Generic Host
|
||||
/// (jeder Worker ist ein <see cref="Microsoft.Extensions.Hosting.IHostedService"/>). Diese Klasse
|
||||
/// stellt die live-bindbare Liste für die Workers-Ansicht bereit und erlaubt den manuellen Trigger.
|
||||
/// </summary>
|
||||
public class WorkerEngine
|
||||
{
|
||||
private readonly IEnumerable<IWorker> _workers;
|
||||
private readonly LoggingService _logger;
|
||||
private readonly ConcurrentDictionary<string, IWorker> _registry = new();
|
||||
private CancellationTokenSource _cts = new();
|
||||
private readonly ConcurrentDictionary<string, IWorker> _registry = new();
|
||||
|
||||
/// <summary>Live-bindbare Liste für dgv_workerlist.</summary>
|
||||
/// <summary>Live-bindbare Liste für die Workers-Ansicht (DataGridView).</summary>
|
||||
public BindingList<WorkerInfo> WorkerInfos { get; } = [];
|
||||
|
||||
public WorkerEngine(IEnumerable<IWorker> workers, LoggingService logger)
|
||||
{
|
||||
_workers = workers;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// ─── Engine-Lifecycle ─────────────────────────────────────────────────────
|
||||
|
||||
public async Task StartAllAsync()
|
||||
{
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
foreach (var worker in _workers)
|
||||
foreach (var worker in workers)
|
||||
{
|
||||
RegisterWorker(worker);
|
||||
|
||||
if (worker.Info.Active)
|
||||
await worker.StartAsync(_cts.Token);
|
||||
_registry[worker.Name] = worker;
|
||||
WorkerInfos.Add(worker.Info);
|
||||
}
|
||||
|
||||
_logger.Info("Core", $"WorkerEngine gestartet – {_registry.Count} Worker/Services registriert.");
|
||||
}
|
||||
|
||||
public async Task StopAllAsync()
|
||||
{
|
||||
await _cts.CancelAsync();
|
||||
|
||||
var tasks = _registry.Values.Select(w => w.StopAsync());
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
_logger.Info("Core", "WorkerEngine gestoppt.");
|
||||
}
|
||||
|
||||
// ─── Einzelsteuerung ──────────────────────────────────────────────────────
|
||||
|
||||
public async Task StartWorkerAsync(string name)
|
||||
{
|
||||
if (!_registry.TryGetValue(name, out var worker)) return;
|
||||
worker.Info.Active = true;
|
||||
await worker.StartAsync(_cts.Token);
|
||||
_logger.Info("Core", $"Worker manuell gestartet: {name}");
|
||||
}
|
||||
|
||||
public async Task StopWorkerAsync(string name)
|
||||
{
|
||||
if (!_registry.TryGetValue(name, out var worker)) return;
|
||||
worker.Info.Active = false;
|
||||
await worker.StopAsync();
|
||||
_logger.Info("Core", $"Worker manuell gestoppt: {name}");
|
||||
logger.Info("Core", $"WorkerEngine: {_registry.Count} Worker/Services registriert.");
|
||||
}
|
||||
|
||||
/// <summary>Löst einen sofortigen manuellen Run des benannten Workers aus.</summary>
|
||||
public async Task TriggerWorkerAsync(string name)
|
||||
{
|
||||
if (!_registry.TryGetValue(name, out var worker)) return;
|
||||
await worker.TriggerAsync();
|
||||
_logger.Info("Core", $"Worker manuell ausgelöst: {name}");
|
||||
}
|
||||
|
||||
// ─── Intern ───────────────────────────────────────────────────────────────
|
||||
|
||||
private void RegisterWorker(IWorker worker)
|
||||
{
|
||||
_registry[worker.Name] = worker;
|
||||
|
||||
// WorkerInfo in BindingList eintragen (UI-Thread, falls nötig)
|
||||
if (WorkerInfos is { } list)
|
||||
{
|
||||
if (SynchronizationContext.Current != null)
|
||||
list.Add(worker.Info);
|
||||
else
|
||||
list.Add(worker.Info);
|
||||
}
|
||||
if (_registry.TryGetValue(name, out var worker))
|
||||
await worker.TriggerAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user