95 lines
2.8 KiB
Dart
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;
|
|
}
|
|
}
|