ag
This commit is contained in:
parent
76c73a30b4
commit
46cc822586
@ -37,3 +37,4 @@ MARKET_HISTORY_RETENTION_DAYS=5
|
||||
# Public API URL baked into Flutter web builds (see scripts/build-production-web.sh).
|
||||
# Use same origin as the site when HAProxy proxies /v1 and /hubs on :443.
|
||||
API_BASE_URL=https://cyberhybridhub.com
|
||||
QUESTION_DISPATCHER_DEBUG_LOGGING_ENABLED=false
|
||||
|
||||
@ -240,6 +240,7 @@ Future<void> main() async {
|
||||
questionService: questionService,
|
||||
questionPipeline: questionPipeline,
|
||||
preferencesDb: questionSourcePreferencesDb,
|
||||
debugLoggingEnabled: env.questionDispatcherDebugLoggingEnabled,
|
||||
);
|
||||
questionPipeline.attachQuestionDispatcher(questionDispatcher);
|
||||
QuestionBackgroundWorker? backgroundWorker;
|
||||
|
||||
@ -21,6 +21,7 @@ class ServerEnv {
|
||||
required this.adminFirebaseUids,
|
||||
required this.marketHistory,
|
||||
required this.alpaca,
|
||||
required this.questionDispatcherDebugLoggingEnabled,
|
||||
});
|
||||
|
||||
final String databaseUrl;
|
||||
@ -29,6 +30,7 @@ class ServerEnv {
|
||||
final bool questionWorkerEnabled;
|
||||
final int questionWorkerIntervalSeconds;
|
||||
final bool questionPipelineTestMode;
|
||||
final bool questionDispatcherDebugLoggingEnabled;
|
||||
|
||||
/// When true, prospective answers earn closeness bonus points and wrong
|
||||
/// direction scores `-2` instead of `-1`. Default false (`+1`/`-1` only).
|
||||
@ -115,6 +117,10 @@ class ServerEnv {
|
||||
.map((String value) => value.trim())
|
||||
.where((String value) => value.isNotEmpty)
|
||||
.toSet();
|
||||
final bool questionDispatcherDebugLoggingEnabled =
|
||||
(env['QUESTION_DISPATCHER_DEBUG_LOGGING_ENABLED'] ?? 'false')
|
||||
.toLowerCase() ==
|
||||
'true';
|
||||
final Map<String, String> stringEnv =
|
||||
Map<String, String>.from(Platform.environment);
|
||||
const List<String> marketHistoryKeys = <String>[
|
||||
@ -158,6 +164,7 @@ class ServerEnv {
|
||||
adminFirebaseUids: adminFirebaseUids,
|
||||
marketHistory: marketHistory,
|
||||
alpaca: alpaca,
|
||||
questionDispatcherDebugLoggingEnabled: questionDispatcherDebugLoggingEnabled,
|
||||
);
|
||||
loaded.assertConsistent();
|
||||
return loaded;
|
||||
|
||||
@ -12,6 +12,7 @@ class QuestionDispatcher {
|
||||
required QuestionService questionService,
|
||||
required QuestionPipeline questionPipeline,
|
||||
required QuestionSourcePreferencesDb preferencesDb,
|
||||
this.debugLoggingEnabled = false,
|
||||
this.maxQueuedQuestions = 3,
|
||||
}) : _questionsDb = questionsDb,
|
||||
_questionService = questionService,
|
||||
@ -22,26 +23,39 @@ class QuestionDispatcher {
|
||||
final QuestionService _questionService;
|
||||
final QuestionPipeline _questionPipeline;
|
||||
final QuestionSourcePreferencesDb _preferencesDb;
|
||||
final bool debugLoggingEnabled;
|
||||
final int maxQueuedQuestions;
|
||||
|
||||
void _log(String message) {
|
||||
if (debugLoggingEnabled) {
|
||||
// ignore: avoid_print
|
||||
print('[QuestionDispatcher] $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximum maintenance passes before giving up on an empty queue.
|
||||
static const int _maxQueueAttempts = 6;
|
||||
|
||||
/// Ensures at least one enabled-source question exists; returns mix-ordered head.
|
||||
Future<Map<String, dynamic>?> dispatchNextQuestion(String firebaseUid) async {
|
||||
_log('dispatchNextQuestion($firebaseUid)');
|
||||
await _questionsDb.ensureUserExists(firebaseUid);
|
||||
|
||||
var rows = await _listEnabledUnansweredOrdered(firebaseUid);
|
||||
_log('Initial unanswered for mix: ${rows.length} rows');
|
||||
for (var attempt = 0;
|
||||
rows.isEmpty && attempt < _maxQueueAttempts;
|
||||
attempt++) {
|
||||
_log('Queue empty, running maintenance (attempt $attempt)');
|
||||
await _runQueueMaintenance(firebaseUid);
|
||||
rows = await _listEnabledUnansweredOrdered(firebaseUid);
|
||||
}
|
||||
|
||||
if (rows.isEmpty) {
|
||||
_log('Still empty after maintenance, returning null');
|
||||
return null;
|
||||
}
|
||||
_log('Returning first row out of ${rows.length}');
|
||||
return _toClientPayload(rows.first, rows.length);
|
||||
}
|
||||
|
||||
@ -84,8 +98,10 @@ class QuestionDispatcher {
|
||||
required String firebaseUid,
|
||||
required Map<String, dynamic> answeredQuestion,
|
||||
}) async {
|
||||
_log('nextQuestionAfterAnswer($firebaseUid)');
|
||||
var rows = await _listEnabledUnansweredOrdered(firebaseUid);
|
||||
if (rows.isEmpty) {
|
||||
_log('Queue empty, falling back to dispatchNextQuestion');
|
||||
return dispatchNextQuestion(firebaseUid);
|
||||
}
|
||||
|
||||
@ -97,6 +113,7 @@ class QuestionDispatcher {
|
||||
final Set<String> allowed = _enabledSourceIds(prefs)
|
||||
.where((String id) => (mix[id] ?? 0) > 0)
|
||||
.toSet();
|
||||
_log('nextQuestionAfterAnswer: mix=$mix, allowed=$allowed, delivered=$delivered');
|
||||
final Map<String, dynamic>? row = await _questionsDb.findHeadUnansweredForMix(
|
||||
firebaseUid,
|
||||
effectiveMixPercent: mix,
|
||||
@ -156,10 +173,12 @@ class QuestionDispatcher {
|
||||
}
|
||||
|
||||
Future<bool> _enqueueOneFromMix(String firebaseUid) async {
|
||||
_log('_enqueueOneFromMix($firebaseUid)');
|
||||
final List<ResolvedQuestionSourcePreference> prefs =
|
||||
await _preferencesDb.getResolved(firebaseUid);
|
||||
final Map<String, int> mix = QuestionSourceMix.effectiveMixFromResolved(prefs);
|
||||
if (mix.isEmpty) {
|
||||
_log('_enqueueOneFromMix: mix is empty');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -169,6 +188,7 @@ class QuestionDispatcher {
|
||||
effectiveMixPercent: mix,
|
||||
deliveredCounts: delivered,
|
||||
);
|
||||
_log('_enqueueOneFromMix: picked primary=$primary (mix=$mix, delivered=$delivered)');
|
||||
final List<String> order = _sourceTryOrderForEnqueue(
|
||||
prefs: prefs,
|
||||
primarySourceId: primary,
|
||||
@ -201,8 +221,10 @@ class QuestionDispatcher {
|
||||
.where((String id) => (mix[id] ?? 0) > 0)
|
||||
.toSet();
|
||||
if (allowed.isEmpty) {
|
||||
_log('_listEnabledUnansweredOrdered: allowed is empty');
|
||||
return <Map<String, dynamic>>[];
|
||||
}
|
||||
_log('_listEnabledUnansweredOrdered: fetching for allowed=$allowed');
|
||||
return _questionsDb.listUnansweredOrderedForMix(
|
||||
firebaseUid,
|
||||
effectiveMixPercent: mix,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user