Multi-Domain Coordination
The Problem: The Evil of Shared Memory
In standard distributed systems, if an App Server needs to wait for a Database to finish booting before it starts, developers usually rely on a shared database lock or rigid, synchronous API calls (e.g., the App constantly pinging db.getStatus() and blocking the thread until it replies).
This creates tight coupling. If the Database takes too long, the App Server's thread times out and crashes. If they try to share a memory state, you risk deadlocks (where both systems are stuck waiting for each other forever).
Ved enforces ADR-002: Absolute Rejection of Shared Mutable State. Domains cannot read each other's memory. They coordinate through asynchronous Mailboxes and Choreography.
Example: Booting an App that Depends on a Database
Here is how Ved coordinates two isolated domains (a Database Provisioner and an App Provisioner) using message passing:
// DOMAIN 1: The Database
domain DatabaseProvisioner {
state {
status: string // "pending" or "ready"
}
goal DBIsReady {
predicate status == "ready"
}
transition BootDB {
step {
if status == "pending" {
emit Infra.CreatePostgres()
// Once created, broadcast the event to the cluster
emit Broadcast(Event::DatabaseReady)
status = "ready"
}
}
}
}
// DOMAIN 2: The Application
domain AppProvisioner {
state {
db_ready: bool
app_status: string
}
goal AppIsLive {
predicate db_ready == true && app_status == "running"
}
// Mailbox Handler: Listens for external events
on Event::DatabaseReady {
db_ready = true
}
transition BootApp {
step {
// It mathematically CANNOT boot until the mailbox receives the DB event
if db_ready == true && app_status != "running" {
emit Infra.StartAppContainer()
app_status = "running"
}
}
}
}
How it Executes (The Control Loop)
- Independent Ticks: Both domains boot up and run on completely isolated CPU slices. They do not share threads.
- The Waiting Game:
AppProvisionerevaluates its goal (AppIsLive). It isfalse. It checks its transitions. Becausedb_readyisfalse, theBootApptransition is blocked. The App Domain safely goes to sleep, consuming zero CPU. - The Catalyst:
DatabaseProvisionerevaluates its goal, triggersBootDB, creates the database, and emits theDatabaseReadyevent to the cluster's message broker. It reaches its goal and goes to sleep. - The Mailbox Delivery: The runtime delivers the
DatabaseReadyevent to theAppProvisioner's mailbox. - The Cascade: The App Domain wakes up, processes its mailbox (
on Event::DatabaseReady), updates its internal state (db_ready = true), and re-evaluates. Suddenly, theBootApptransition unlocks! It executes, starts the app, and finally reaches its stable goal.
Behavior
- Producer emits messages
- Consumer processes messages
- No shared state
Why This Matters
Traditional systems:
- require locks
- risk race conditions
Ved:
- message-based coordination
- deterministic interaction
Key Takeaways
1. Deadlock Immunity
Because domains never share memory or wait on synchronous network calls, deadlocks are mathematically impossible. The App domain isn't holding a thread open waiting for the DB; it is completely asleep. It only wakes up when the mailbox has mail.
2. Decoupled Blast Radiuses
If the DatabaseProvisioner domain crashes due to a weird hardware fault right after it emits the event, the AppProvisioner domain doesn't care. It already got the message. The App boots successfully while the runtime automatically reboots the DB domain in the background. In a tightly coupled Python script, if the DB function crashes, the whole script exits, and the App never boots.
3. Eventual Consistency as a Superpower
Most developers are terrified of "Eventual Consistency" (the idea that system A knows something, but system B won't find out for a few milliseconds). Ved leans into it. The AppProvisioner doesn't actually know if the database is currently running; it only knows that its internal state says db_ready = true. This forces developers to design highly resilient systems that can handle being out of sync temporarily.
4. Safe "Scale-Out" Architecture
Because these domains don't share memory, they don't even have to live on the same physical server. The Ved runtime could execute the Database domain on a server in Tokyo and the App domain on a server in Mumbai. The logic remains 100% identical. The runtime handles the cross-border message delivery. You write the code for a single machine, and the runtime scales it globally for free.
Summary
Coordination becomes:
explicit message flow instead of shared state