资讯详情

资讯详情

MooTool 桌面端自动更新检查调度:Compose 版对齐 Electron 的 2.5s 首检与 60 分钟周期机制

桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载导读本文围绕 MooTool 新一代 Compose 桌面端next-compose的更新检查调度改造对应 DIFF-409 设计文档展开剖析其如何将 Electron 版启动 2.5 秒后首检、之后每 60 分钟复检的调度行为对齐到 Compose 实现中并解决此前仅启动时立即检查、且关闭开关后无法终止检查链的问题。读完本文你将掌握UpdateAutoCheckScheduler的调度状态机、它在AppContainer启动/关闭/设置变更三条路径上的挂载方式、与UpdateCoordinator.check(autoDownload, automatic)的调用约定以及对应的测试验证手段。一、背景为什么 Compose 需要周期性更新检查更新检查是桌面应用的基本能力但其调度策略直接影响用户体验检查太频繁会无谓占用网络与电量太稀疏又会让用户错过安全修复。MooTool 的 Electron 实现见 next/electron/main/index.ts中configureUpdateChecks的调度契约是当autoCheckUpdates开启时启动后 2.5 秒2500ms执行首次checkForUpdatesAndBroadcast此后每 60 分钟3600000ms重复一次当autoCheckUpdates关闭时清除clearTimeout/clearInterval已注册的定时器彻底停止检查链。而 Compose 版改造前的行为存在两个缺陷无周期调度仅在startBackgroundTasks中立即检查一次之后应用长期运行也不会再复查用户无法及时感知新版本关闭开关失效用户关闭启动后检查更新后已经发起或正在发起的检查任务链无法被停止属于状态泄漏。DIFF-409 的目标正是用一套可重配置、可取消的协程调度器取代一次性检查使 Compose 与 Electron 的调度语义完全对齐。二、调度参数与生命周期契约DIFF-409 明确了两个核心常量二者由独立对象UpdateAutoCheckTiming承载便于在测试中直接断言详见 UpdateAutoCheckScheduler.kt常量值语义Electron 对应STARTUP_DELAY_MS2_500L启动后延迟首次检查的毫秒数setTimeout(..., 2500)INTERVAL_MS3_600_000L60×60×1000两次周期检查之间的毫秒数setInterval(..., 60*60*1000)调度器的生命周期契约共三条可重配置AppContainer.configureAutomaticUpdateChecks()在启动时与autoCheckUpdates设置变更时调用reconfigure()可停止close()时调用stop()取消已调度的协程任务每次检查仍走统一入口无论手动还是自动最终都进入UpdateCoordinator.check(autoDownload …, automatic true)自动检查的 UI 静默策略由 DIFF-410 另行约束后文详述。三、源码解析基于协程的UpdateAutoCheckSchedulerUpdateAutoCheckScheduler的核心是一个延迟 → 循环 → 每次检查后再次延迟的协程循环完整实现如下UpdateAutoCheckScheduler.ktobject UpdateAutoCheckTiming { const val STARTUP_DELAY_MS 2_500L const val INTERVAL_MS 60 * 60 * 1_000L } class UpdateAutoCheckScheduler( private val scope: CoroutineScope, private val enabled: () - Boolean, private val autoDownload: () - Boolean, private val check: (autoDownload: Boolean) - Unit, private val startupDelayMs: Long UpdateAutoCheckTiming.STARTUP_DELAY_MS, private val intervalMs: Long UpdateAutoCheckTiming.INTERVAL_MS, ) { private var job: Job? null fun reconfigure() { job?.cancel() job null if (!enabled()) return job scope.launch { delay(startupDelayMs) while (isActive) { check(autoDownload()) delay(intervalMs) } } } fun stop() { job?.cancel() job null } }实现要点逐条拆解构造器函数式注入enabled、autoDownload、check均为函数引用而非固定值这使得调度器无需感知设置存储细节也保证每次检查时都能读取到最新的autoDownloadUpdates状态startupDelayMs/intervalMs可覆盖默认定时来自UpdateAutoCheckTiming但测试可以用毫秒级小数值如 15ms 首延、100ms 周期快速驱动验证不必真实等待 2.5 秒与 60 分钟reconfigure()是幂等且可取消的先job?.cancel()再置空若enabled()为假则直接返回等效 Electron 的clearTimeoutclearInterval分支为真则用scope.launch重建循环。旧协程被取消新协程重新计时所以关闭后再开启时首检会重新经历 2.5 秒延迟与 Electron 行为一致循环用while (isActive)而不是while (true)isActive是协程 Job 的活性标志配合delay的可取消语义stop()调用job.cancel()后循环会在下一次delay处立即中断不会漏电继续检查——这正是改造前无法停止已发起检查任务链问题的解法。从结构看该调度器采用了策略注入 状态持有 Job的极简设计不持有任何设置对象、不感知 UI只负责什么时候调用check检查逻辑本身完全委托给外部的UpdateCoordinator。四、生命周期挂载AppContainer 中的启动、变更与关闭调度器在 AppContainer.kt 中实例化三个函数式依赖直接指向实时设置private val updateAutoCheckScheduler UpdateAutoCheckScheduler( scope scope, enabled { _settings.value.general.autoCheckUpdates }, autoDownload { _settings.value.general.autoDownloadUpdates }, check { autoDownload - updates.check(autoDownload autoDownload, automatic true) }, )三条挂载路径启动startBackgroundTasks()首先调用configureAutomaticUpdateChecks()AppContainer.kt而AppContainer.create(...)在构造完成后通过.also { it.startBackgroundTasks() }触发即应用一启动就按设置决定是否进入调度设置变更updateSettings(transform)内比较previous.general.autoCheckUpdates ! next.general.autoCheckUpdates一旦切换就调用configureAutomaticUpdateChecks()AppContainer.kt。注意这里只对autoCheckUpdates做变更检测——autoDownloadUpdates的从关到开属于另一个场景触发立即下载见 DIFF-411不参与调度重建关闭close()中先updateAutoCheckScheduler.stop()再updates.cancel()AppContainer.kt确保退出时不再发起新的检查。configureAutomaticUpdateChecks()本体只是一行委托AppContainer.kt但它是一个语义明确的命名入口让启动时与设置变更时两条路径共享同一套重配置逻辑。五、检查的最终去处UpdateCoordinator 的统一入口调度器发出的每一次check(autoDownload)都进入UpdateCoordinator.checkUpdateCoordinator.ktfun check( currentVersion: String ProductIdentity.VERSION, autoDownload: Boolean false, automatic: Boolean false, ) { replaceJob { if (!automatic) { _state.value _state.value.copy(busy true, error , message , status checking) } runCatching { withContext(Dispatchers.IO) { UpdateEngine.fetchAndCheck(currentVersion, UpdateEngine.detectIdentity(), feedUrl, textFetcher) } }.onSuccess { result - val ready result.download?.let { downloader.readyFile(it) } if (UpdateCheckSurfacing.shouldApplyUiResult(automatic, result.status)) { _state.value UpdateUiState(/* 写入 UI */) } if (autoDownload result.status UpdateCheckStatus.Available result.download ! null ready null) { performDownload() } }.onFailure { error - if (UpdateCheckSurfacing.shouldApplyUiError(automatic)) { _state.value _state.value.copy(busy false, status error, ...) } } } }值得注意的两点实现事实automatic true表示静默检查不置busy状态、不主动改写关于页 UI只有发现新版本Available时才把结果写入 UI已是最新Latest、未发布Unpublished或网络失败都不打扰用户。这一静默策略由UpdateCheckSurfacing承载UpdateCheckSurfacing.ktshouldApplyUiResult(automatic, status)仅在非自动或自动且 Available时返回真shouldApplyUiError(automatic)仅对手动检查返回真对应 ElectroncheckForUpdatesAndBroadcast中automatic 且非 available 不广播、automatic 错误不广播的分支next/electron/main/index.tsautoDownload不依赖 UI 刷新即使静默检查未改写 UI只要发现Available且autoDownload()为真仍会执行performDownload()保证后台发现新版本即自动下载这一能力与调度器解耦。检查背后的网络层在UpdateEngine中UpdateEngine.kt默认拉取update-manifest.jsonDEFAULT_FEED通过detectIdentity()按os.name/os.arch判定darwin/win32/linux平台与架构UpdateCoordinator的 OkHttp 客户端还强制校验请求 URL 必须为 HTTPSrequireHttps并设置 15 秒连接超时、60 秒读超时。六、设置入口与默认值设置模型中GeneralSettings的默认值是autoCheckUpdates true、autoDownloadUpdates falseSettings.kt即默认开启自动检查但默认不自动下载用户入口在设置页通用General分类下两个Toggle分别绑定启动后检查更新与有更新时自动下载切换时调用container.updateSettings { ... }走上面描述的变更检测路径SettingsScreen.kt国际化文案在 Translator.kt 中对应为settings.autoCheckUpdates → 启动后检查更新、settings.autoDownloadUpdates → 有更新时自动下载旧版 Java 配置迁移时autoCheckUpdate从setting.common段读取默认true说明该开关是对历史行为的延续LegacyJavaSettings.kt。七、验证测试与离线命令DIFF-409 的验证由UpdateAutoCheckSchedulerTest覆盖UpdateAutoCheckSchedulerTest.kt四个用例恰好对应四个契约测试断言目标timingMatchesElectron常量精确等于 2500ms 与 3600000ms锁定与 Electron 的时序对齐runsCheckAfterStartupDelayWhenEnabled开启时延迟到达前不触发delay(5)后checks 0延迟后恰好触发一次passesLatestAutoDownloadFlagOnEachCheck每次检查传入的autoDownload是最新值首检为 false将开关翻转为 true 后下一周期收到 truedoesNotScheduleWhenDisabledenabled { false }时等待远超调度周期仍为 0 次检查其中第二个用例用waitUntil轮询工具5ms 轮询、带超时驱动协程测试第三个用例证明每周期读取最新autoDownload这一设计——这与 ElectronsetInterval回调每次读取最新设置的行为一致。静默策略侧由 UpdateCheckSurfacingTest.kt 补充验证手动检查automaticfalse对Latest/Unpublished/错误一律展示自动检查automatictrue仅Available上屏错误不展示。统一执行验证命令仓库 next-compose 根目录下./gradlew :composeApp:desktopTest --offline该命令以离线模式运行desktopTest任务适合在无网络环境下复跑全部桌面端单测包括上述调度器与静默策略测试。八、小结与延伸阅读DIFF-409 用一个约 40 行的协程调度器把 Electron 的2.5s 首检 60min 周期 开关即停三要素完整移植到 Compose 桌面端并通过构造器注入、幂等reconfigure()、可取消stop()三处设计解决了旧实现的无周期、关不掉问题。它只负责何时检查检查动作委托给UpdateCoordinator静默策略委托给UpdateCheckSurfacing职责边界清晰便于独立演进与测试。与本次改造直接相关的后续链路可继续阅读自动检查的 UI 静默策略DIFF-410打开自动下载时续传可用更新DIFF-411Electron 端调度与广播实现参照赞分享桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载相关推荐MooTool Compose 版 JSON 检查器 1321dp 断点与 Electron 版布局行为的对齐实现MooTool Compose 版 JSON 检查器 1321dp 断点与 Electron 版布局行为的对齐实现 在 MooTool 的多端移植中Elec桌面应用开发工具MooTool Compose 版 JSON Vault「打开目录与刷新」实现机制解析Electron 对齐MooTool Compose 版 JSON Vault「打开目录与刷新」实现机制解析Electron 对齐 JSON Vault 是 MooTool 中用桌面应用开发工具MooTool Next Compose JSON 检查器分区顺序对齐方案从 Electron 基准到 Compose 独立卡片MooTool Next Compose JSON 检查器分区顺序对齐方案从 Electron 基准到 Compose 独立卡片 MooTool Next C桌面应用开发工具上一篇PaddleNLP 小样本层次文本分类实战基于 ERNIE 3.0 提示学习的完整训练与部署指南下一篇SteamCleaner终极游戏缓存清理工具3步轻松释放100GB硬盘空间创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →