runNow

@ObjCName(swiftName = "run")
suspend fun <R> runNow(taskId: String, task: suspend () -> R): R

Run task immediately under taskId and suspend until it completes, returning the typed result R.

Semantics — "raw" background dispatch. Unlike scheduled work (schedule + register), runNow:

  • runs immediately, with no WorkConstraints, no BackoffPolicy, no retries, no ExecutionHint gating;

  • does not consult WorkerRegistry — the task lambda is the work, and taskId does not need to be register()-ed first;

  • is routed through the OS scheduling primitive on Android (WorkManager) and iOS (BGTaskScheduler) so the work earns background runtime if the app is suspended mid-call; on macOS and the JVM it runs on a library-owned SupervisorJob scope (NSBackgroundActivityScheduler is interval-shaped and a poor fit for one-shot work; the JVM has no platform scheduler at all).

Pre-emption — "last call wins". If a runNow is already in flight for taskId, or a scheduled run for taskId is pending or executing, runNow cancels them all (via cancel) before submitting its own request. The prior caller's await rethrows CancellationException. This is necessary because runNow returns a typed result to a specific caller — two concurrent runs for the same id would be ambiguous.

Cancellation. Caller cancellation flows through structured concurrency: the OS request is cancelled (best-effort on iOS — BGTaskScheduler cannot kill a running handler, only pending requests; an in-flight lambda is cancelled via the in-process bridge Job), the task lambda observes CancellationException, and runNow rethrows.

Exceptions. A Throwable thrown by task propagates to the caller's await. The platform layer reports WorkResult.Failure to the OS so it doesn't treat the process as crashed. SKIE bridges this as Swift async throws -> R.

iOS Info.plist requirement. taskId must appear in the app's BGTaskSchedulerPermittedIdentifiers array. If it does not, BGTaskScheduler.submit rejects the request and runNow throws an IllegalStateException whose message names the missing identifier.

Throws

if start has not been called yet, or the platform refuses the request (iOS only — see above).