cyberhybridhub/server/lib/workers/question_background_worker.dart
2026-05-31 11:17:12 -05:00

95 lines
2.8 KiB
Dart

import 'dart:async';
import 'dart:io';
import 'package:meta/meta.dart';
import '../pipeline/question_pipeline.dart';
import '../trading/trading_orchestrator.dart';
import 'market_history_scheduler.dart';
/// Runs [QuestionPipeline.runMaintenanceCycle] on a fixed interval, and
/// optionally [TradingOrchestrator.runMaintenanceCycle] right after when
/// trading is enabled.
///
/// When [marketHistoryScheduler] is set, [MarketHistoryScheduler.runIfDue]
/// runs at the start of each tick (before the question pipeline).
class QuestionBackgroundWorker {
QuestionBackgroundWorker({
required QuestionPipeline pipeline,
required Duration interval,
TradingOrchestrator? tradingOrchestrator,
MarketHistoryScheduler? marketHistoryScheduler,
Future<void> Function()? tradingMaintenanceRunner,
DateTime Function()? clock,
}) : _pipeline = pipeline,
_interval = interval,
_tradingOrchestrator = tradingOrchestrator,
_marketHistoryScheduler = marketHistoryScheduler,
_tradingMaintenanceRunner = tradingMaintenanceRunner,
_clock = clock ?? DateTime.now;
final QuestionPipeline _pipeline;
final TradingOrchestrator? _tradingOrchestrator;
final MarketHistoryScheduler? _marketHistoryScheduler;
final Future<void> Function()? _tradingMaintenanceRunner;
final DateTime Function() _clock;
final Duration _interval;
Timer? _timer;
bool _running = false;
void start() {
if (_timer != null) {
return;
}
stdout.writeln(
'Question background worker started (interval ${_interval.inSeconds}s, '
'trading=${_tradingOrchestrator != null || _tradingMaintenanceRunner != null}, '
'marketHistory=${_marketHistoryScheduler != null})',
);
_timer = Timer.periodic(_interval, (_) => _tick());
unawaited(_tick());
}
void stop() {
_timer?.cancel();
_timer = null;
_pipeline.close();
}
@visibleForTesting
Future<void> runTickForTest() => _tick();
Future<void> _tick() async {
if (_running) {
return;
}
_running = true;
if (_marketHistoryScheduler != null) {
try {
await _marketHistoryScheduler.runIfDue(_clock());
} catch (e, st) {
stderr.writeln('Market history scheduler tick failed: $e\n$st');
}
}
try {
await _pipeline.runMaintenanceCycle();
} catch (e, st) {
stderr.writeln('Question background worker tick failed: $e\n$st');
}
if (_tradingMaintenanceRunner != null) {
try {
await _tradingMaintenanceRunner();
} catch (e, st) {
stderr.writeln('Trading orchestrator tick failed: $e\n$st');
}
} else if (_tradingOrchestrator != null) {
try {
await _tradingOrchestrator.runMaintenanceCycle();
} catch (e, st) {
stderr.writeln('Trading orchestrator tick failed: $e\n$st');
}
}
_running = false;
}
}