The ephemeral flag¶
What it solves¶
A persisted background job can fire before your app's init is finished — especially on Android, where JobScheduler may dispatch a worker as soon as constraints are satisfied, including during the brief window between the OS launching your process and Application.onCreate finishing.
Without protection, the worker tries to resolve dependencies against a half-initialised app graph, or worse, runs with stale state from a previous version of the app schema. Either is a foot-gun.
WorkRequest.ephemeral = true declares: this work must be re-scheduled by app code after init; do not run it from a state I didn't deliberately put it in.
Contract¶
- On every cold start of the app process, the library erases all ephemeral entries before the platform scheduler has a chance to dispatch them.
- The user re-schedules ephemeral jobs from app code at a known-safe initialisation point.
- Non-ephemeral jobs are unaffected — they continue to be persisted and survive process death normally.
Sweep timing per platform¶
| Platform | "Cold start" means | Sweep timing |
|---|---|---|
| Android | Application.onCreate is running for a fresh process. |
Inside Backgrounder.create(application) — the constructor runs the sweep eagerly before returning. |
| iOS | A new process invocation of application(_:didFinishLaunchingWithOptions:). |
Top of backgrounder.start() (before any BGTaskScheduler.register(...)). |
| macOS | A new process invocation of applicationDidFinishLaunching. |
Top of backgrounder.start() (same as iOS). |
Android backstop¶
Even with the sweep, there's a tiny window on Android where JobScheduler could fire a worker between the OS launching your process and Backgrounder.create(...) running. The library defends against this with a per-instance AtomicBoolean ready-gate:
Backgrounder.create(...)initialises the gate tofalse.backgrounder.start()flips it totrue— call this once any further app-side init the workers depend on is complete.- Inside
RegistryDispatchWorker.doWork(), ephemeral requests check the gate; iffalse, the worker returnsWorkResult.Failure("dispatched before ephemeralReady")immediately without invoking user code. WorkManager's normal retry behaviour will pick the work up again on the next dispatch — by which timestart()will have run.
When to use it¶
- Worker depends on app state initialised after
Application.onCreate(typical: anything resolved through your DI graph that itself requires initialised dependencies). - Worker reads from a database whose schema may have changed across app updates and you'd rather have user code re-schedule with the migrated state.
- Worker uses input data whose interpretation has changed across app versions.
When not to use it: workers that are genuinely self-contained (e.g. POSTing a queued event payload to a server) — those should survive process death and reboot, and ephemeral = false is the right default.