Skip to content

MOB as a 'background process' #18

@andyl

Description

@andyl

I've got no mobile experience, and am curious how to use MOB as a 'background process' that responds to events from a server.

Here is my Q&A with Claude - posted FYI. Is the answer correct?

If useful, I could rewrite as a guide for the README or standalone tutorial doc. LMK if a PR would be welcome.

QUESTION:

with the MOB approach, could my app run as a background task on the phone, and respond to messages sent from a server?

ANSWER:

Short answer: technically yes from BEAM's perspective, but practically no — the mobile OSes don't let you do this the way you'd want, and it's not really about Mob's design.

The thing to understand is that on iOS and Android, "background" doesn't mean what it means on a server. Your app process doesn't get to just sit there running a GenServer loop, polling, or holding an open Erlang distribution connection indefinitely. Both OSes aggressively suspend or kill backgrounded apps to save battery, and they're the gatekeepers for what wakes you back up.

Here's what each platform actually allows:

iOS is the stricter of the two. Once your app is backgrounded, the OS suspends the entire process within seconds — that means the BEAM scheduler stops, all GenServers freeze in place, sockets get torn down, and your Erlang distribution connection dies. To get woken up, you have to go through one of Apple's sanctioned mechanisms: silent push notifications via APNs (content-available: 1), background fetch (OS decides when, you don't), background tasks (BGTaskScheduler — also OS-scheduled, not on demand), VoIP push (PushKit, but only if you're actually a VoIP app), or specific entitlements like audio playback, location updates, or Bluetooth. When one of those fires, the OS gives you a short execution window (typically ~30 seconds for silent push) to do work, then suspends you again. So with Mob, the flow would be: server sends APNs push → iOS wakes your app → native shell starts/resumes the BEAM → BEAM runs whatever handler → BEAM gets suspended again. The BEAM is not a long-running listener.

Android is more flexible but heading in the same direction. Foreground services (with a persistent notification) can keep a process alive indefinitely, which means your BEAM could genuinely stay running and hold a distribution or WebSocket connection. Without that notification, recent Android versions (especially 12+) heavily restrict background execution. The standard pattern for server-pushed messages is FCM (Firebase Cloud Messaging) — server sends to FCM, FCM wakes your app, you handle the message in a short window. WorkManager handles deferred background tasks. So on Android, if you're willing to show a persistent notification, you could keep the BEAM running as a real always-on node; otherwise you're in the same push-driven model as iOS.

For Mob specifically, none of this is in the README yet. The framework is currently focused on the foreground UI loop — screens as GenServers, native rendering, hot code reload during development. To make background server-push work, the native host (Swift/Objective-C on iOS, Kotlin/Java on Android) would need to:

  1. Register for APNs/FCM and forward incoming pushes into the BEAM via NIF call.
  2. Manage BEAM lifecycle correctly — cold-starting it if suspended, or keeping it warm if Android foreground service.
  3. Cleanly tear down and re-establish any distribution / WebSocket connections when the OS suspends and resumes the process.

The Mob.Notify.register_push API the README mentions suggests they're at least thinking about the push side, but I don't see anything yet about "BEAM stays alive in the background and responds to messages from a server" as a first-class feature.

So the realistic architecture for what you described:

  • Your server pushes via APNs (iOS) or FCM (Android) — not direct to a socket.
  • The push wakes the native app, which spins up or resumes the BEAM.
  • A GenServer handler runs for ~30 seconds and does whatever work (update local state, fetch data, show a notification, sync).
  • BEAM goes back to sleep.

If you need true always-on (e.g., a chat app holding a live connection), Android foreground service is your only real path on either OS, and iOS will fight you the whole way. This isn't a BEAM-on-mobile limitation — it's a fundamental mobile OS reality that React Native, Flutter, native, and Mob all have to deal with the same way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions