From d4364b2a1a9bec4a8d2fc423c23043fb91513aae Mon Sep 17 00:00:00 2001 From: yibo Date: Thu, 4 Jun 2026 18:58:54 +0800 Subject: [PATCH] fix(lifelog/summary): 修 worker 并发把 llama-server 搞 502 --- lifelog-recorder/app/src/main/kotlin/com/lemon/lifelog/summary/SummaryWorker.kt | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lifelog-recorder/app/src/main/kotlin/com/lemon/lifelog/summary/SummaryWorker.kt b/lifelog-recorder/app/src/main/kotlin/com/lemon/lifelog/summary/SummaryWorker.kt index 77f1da9..d620bae 100644 --- a/lifelog-recorder/app/src/main/kotlin/com/lemon/lifelog/summary/SummaryWorker.kt +++ b/lifelog-recorder/app/src/main/kotlin/com/lemon/lifelog/summary/SummaryWorker.kt @@ -51,6 +51,13 @@ class SummaryWorker( * 端点/model 由 ChatConfig 解析(与对话共用配置)。 */ const val KEY_BACKEND = "summary_backend" + /** 防并发:periodic + one-shot + RETRY 可能同时触发,多个 worker 并发打同一个 + * llama-server 会把上游搞 502(实测)。进程内 flag 保证同时只跑一个 worker body。 */ + private val isRunning = java.util.concurrent.atomic.AtomicBoolean(false) + + /** 单轮时间预算:超了就停、剩余会话下轮继续,避开 WorkManager ~10min 执行上限。 */ + const val RUN_BUDGET_MS = 7 * 60 * 1000L + /** 纯函数:把按时间排好序的段切成若干会话。 */ fun groupSessions(segments: List, gapMs: Long): List> { val out = mutableListOf>() @@ -71,6 +78,19 @@ class SummaryWorker( private val shortFmt = SimpleDateFormat("MM-dd HH:mm", Locale.US) override suspend fun doWork(): Result { + if (!isRunning.compareAndSet(false, true)) { + Log.i(TAG, "another run in progress, skip") + return Result.success() + } + return try { + runSessions() + } finally { + isRunning.set(false) + } + } + + private suspend fun runSessions(): Result { + val runStart = System.currentTimeMillis() val now = inputData.getLong(INPUT_NOW_TS, System.currentTimeMillis()) val prefs = applicationContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE) val gapMs = inputData.getLong(INPUT_GAP_MS, 0L).takeIf { it > 0 } @@ -111,6 +131,11 @@ class SummaryWorker( // 已总结过(时间范围重叠)跳过。 if (existing.any { it.windowStartTs <= end && it.windowEndTs >= start }) { skipped++; continue } + if (System.currentTimeMillis() - runStart > RUN_BUDGET_MS) { + SummaryProgress.line("⏸ 本轮时间到,剩余会话下次继续") + break + } + val userPrompt = buildPrompt(repo, session, speakerNames, start, end) if (userPrompt == null) { skipped++; continue } // 整段无有效转写 @@ -142,7 +167,9 @@ class SummaryWorker( SummaryProgress.finish("完成:$made 篇生成,$skipped 个会话跳过(共 ${sessions.size})") Log.i(TAG, "done: ${sessions.size} sessions, $made summarized (gap=${gapMs / 60_000}min)") - return if (anyFailed && made == 0) Result.retry() else Result.success() + // 不 retry:失败/未处理的会话下一轮 periodic 或手动「现在跑一次」会重新捡, + // 避免 502 后 WorkManager 死循环 hammering。 + return Result.success() } /** 拼 prompt;若会话内没有任何有效转写返回 null。 */ -- libgit2 0.21.4