Skip to content

feat: unify runtime function scheduling#8

Open
V3RON wants to merge 1 commit into
mainfrom
feat/unify-api
Open

feat: unify runtime function scheduling#8
V3RON wants to merge 1 commit into
mainfrom
feat/unify-api

Conversation

@V3RON
Copy link
Copy Markdown
Collaborator

@V3RON V3RON commented May 26, 2026

Why this matters

Runtime functions and headless tasks represented the same product idea: run registered JavaScript on a named runtime without mounting UI. Keeping them as separate concepts made the API harder to teach, harder to type, and harder to mirror consistently across JS and native callers.

This PR unifies that model around runtime functions. A runtime function is now the single unit of background work, and the caller chooses whether it needs a result or only needs the work accepted/queued. That gives app authors one registration model, one Metro discovery path, one native queue, and one mental model for cross-runtime work.

New API structure

The JS API now has two primary invocation shapes:

await call(runtimeFunction).on(runtimeName)(...args);
await schedule(runtimeFunction).on(runtimeName)(...args);
  • call(...) is awaitable and returns the runtime function result.
  • schedule(...) is fire-and-forget from the function-result perspective. Its promise resolves when native accepts or queues the work.
  • schedule(...) is typed to accept only runtime functions whose resolved return type is void.
  • Metro keeps directive shortcuts as awaitable call semantics.
  • Runtime function helpers expose runOn(...) for awaitable calls and scheduleOn(...) for scheduled calls.

Native callers now use the same vocabulary:

ThreadedRuntime.call(context, runtimeName, functionId, argsJson, promise)
ThreadedRuntime.schedule(context, runtimeName, functionId, argsJson)

C++/Objective-C++ scheduling uses:

nativecompose::threadedruntime::schedule(runtimeName, functionId, argsJson);

Summary of changes

  • Removes the separate headless task registry and dispatch path.
  • Adds schedule to the JS public API, native modules, Android/iOS runtime queues, C++ dispatcher, and Nitro runtime-function surface.
  • Keeps call and schedule on a shared per-runtime queue so dispatch order is preserved.
  • Updates Metro transformation so schedule(fn).on(runtime)(...) compiles to fn.scheduleOn(runtime, ...).
  • Converts the two-runtime example from headless task registration to named scheduled runtime functions.
  • Updates docs to describe background work through scheduled runtime functions instead of headless tasks.

Verification

  • bunx tsc --noEmit -p example/tsconfig.json
  • ./gradlew :app:compileDebugKotlin
  • ./gradlew :react-native-runtimes_core:externalNativeBuildDebug
  • In-memory TypeScript check confirms schedule(runtimeFunction(() => 1)) is rejected.
  • bun test:harness --harnessPlatform=ios
  • bun test:harness --harnessPlatform=android

@V3RON V3RON force-pushed the feat/unify-api branch from df179e3 to 296eeee Compare May 26, 2026 08:38
Replace separate headless task dispatch with scheduled runtime functions. Add call/schedule APIs across JS, native bridge, Nitro, examples, and docs so awaitable and fire-and-forget work share one registration model.
@V3RON V3RON force-pushed the feat/unify-api branch from 296eeee to 1cc63f0 Compare May 26, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant