v3.3.0
·
129 commits
to main
since this release
Removed
- BREAKING — Koin is no longer a dependency.
koin-coreshipped atruntimescope in all
five published artifacts, so consumers who never used Koin still carried it on the classpath
and in the iOS klib link (#66).
kmpWorkerModule()andkmpWorkerCoreModule()are removed; callKmpWorkManager.initialize()
instead. The migration is roughly four lines in one file — see
docs/MIGRATION_V3.3.0.md. Koin and Hilt users keep working by
bindingKmpWorkManager.getInstance()from their own module; the library deliberately does
not ship a bridge artifact. koin-androiddropped from the Android artifact (#67).
No production code imported it — it was only surviving because it transitively supplied
androidx.core(NotificationCompat), which is now declared directly.
Added
- iOS:
KmpWorkManager.initialize()— a DI-agnostic entry point mirroring Android's,
keeping the eager fail-fast checks (IosWorkerFactorytype, Info.plist
BGTaskSchedulerPermittedIdentifiers) at the same point in startup
(#68). KmpWorkManagerInstance.workerFactoryon Android, for hosts that run workers outside
WorkManager (a custom exact-alarmBroadcastReceiver, for example) and need to resolve a
worker by class name themselves.- Registry hardening suites —
V330RegistryHardeningTest(iOS) and
V330AndroidRegistryHardeningTest(Robolectric) — covering concurrent init election,
concurrent readers againstby lazy, init/shutdown leak loops, startup-path init cost,
cached-resolution cost, hostile worker class names, and fail-fast before state is published.
Fixed
- iOS: execution history and task events were silently dropped.
EventStoreand
ExecutionHistoryStorewere lazysingle { }bindings whose global-registration side
effects only ran if something resolved them — and nothing in the library or the sample ever
did. Unless a host app resolved them itself,KmpWorkManagerRuntime.executionHistoryStore
stayednull, workers dropped every record through?.save(record), and
getExecutionHistory()returned an empty list. Android was already correct via
createdAtStart = true. Both stores are now created eagerly on both platforms. shutdown()left stale global registrations.TaskEventManager.initialize()is
compare-and-set "first call wins", and neither platform'sshutdown()released the claim, so
shutdown()→initialize()left the global event store pointing at the dead registry's
instance while the live registry held a different one.shutdown()now releases both the
event store and the execution history store.- iOS: nested-timeout misattribution could theoretically survive under CPU starvation.
ChainExecutor.executeChain/executeStepdisambiguated an inner (chain/task) timeout from
an outer one viaelapsedNow() < timeoutinsidecatch (TimeoutCancellationException).
Correct under normal load, but a scheduling stall between the outer cancellation and the
elapsed-time read could pushelapsedpast the inner budget and misattribute an outer
cancellation as a genuine chain/task timeout. Both call sites now wrap their inner block in
withTimeoutOrNullinstead ofwithTimeout— kotlinx.coroutines identity-checks the
exception internally, so there is no elapsed-time read on this path at all, and no window
for the race. SeeV330TimeoutIdentityDisambiguationTest. - Android:
OverflowFileRegistrycould leak files in multi-process apps. The
SharedPreferences-backed registry caches in memory perContext, so a host with separate
processes (:background,:push, …) could race aregister()in one process against a
consumeAndDelete()in another and leak the overflow file until the 24 h janitor sweep. Now
backed by one file per entry undercacheDir/overflow_registry/, with no per-process cache to
race. Task ids are caller-supplied, so filenames are derived via an injective, traversal-safe
percent-encoding rather than a hash. Migrates any legacySharedPreferencesentries
automatically on first use.
Changed
KmpWorkManagerKoin→KmpWorkManagerAndroid, backed byAndroidServiceRegistry; the iOS
equivalent isIosServiceRegistry. Both are plain internal registries ofby lazy
singletons — the Koin module never used a container feature (no scopes, no qualifiers, no
parametersOf, no lazy graph).- Documentation swept for the removed API: README, quickstart, platform-setup, api-reference,
examples, troubleshooting, the KSP README, and the@Worker/BgTaskIdProviderKDoc.
Install
implementation("dev.brewkits:kmpworkmanager:3.3.0") // core engine (no Ktor)
implementation("dev.brewkits:kmpworkmanager-http:3.3.0") // optional — Ktor 3 HTTP workers