Overview
The flora runtime is a multi-threaded Rust service that bridges Discord events to JavaScript isolates. It uses V8 (via Deno Core) to execute guild scripts in isolated environments with configurable resource limits.Core Components
BotRuntime
The main runtime coordinator that manages a pool of worker threads. Each worker can host multiple guild isolates. Source:apps/runtime/src/runtime/mod.rs:34
- Worker pool initialization
- Guild-to-worker routing (consistent hashing)
- Event dispatch coordination
- Runtime migration between workers
Worker Threads
Each worker runs on a dedicated thread with its own tokio runtime. Workers handle multiple guild isolates and one default runtime. Source:apps/runtime/src/runtime/worker.rs:44
- Listen for commands via unbounded channel
- Execute cron tick every second
- Process commands: deploy, dispatch, migrate, update secrets
- Manage guild isolates lifecycle
apps/runtime/src/runtime/worker.rs:84
JavaScript Runtime State
Each guild has an isolated V8 runtime with its own event loop, dispatch function, and secrets.- Separate V8 isolate per guild
- No shared global state between guilds
- Independent event loops
- Per-guild secret scopes
Service Layer
DeploymentService
Manages guild script deployments stored in PostgreSQL and cached in Redis. Operations:- Upsert deployment (bundle + source map)
- Retrieve deployment by guild ID
- List all deployments for cache restoration
- Invalidate cache on updates
apps/runtime/src/services/deployments/mod.rs
KvService
Provides per-guild key-value storage backed by Sled (on-disk) and indexed in PostgreSQL. Storage model:- Guild-scoped stores (multiple per guild)
- Sled databases at
./data/kv/{guild_id}/{store_name} - Metadata tree for expiration and custom metadata
- In-memory LRU cache of Sled instances
apps/runtime/src/services/kv/service.rs:24
SecretService
Encrypts and manages guild secrets using ChaCha20-Poly1305. Features:- Master key encryption
- Per-guild secret runtime data
- Secret scope thread-local storage
- Placeholder derivation for safe references
apps/runtime/src/services/secrets/mod.rs
AuthService
Handles Discord OAuth flow and session management via Redis. Flow:- User authorizes via Discord OAuth
- Exchange code for access token
- Store session in Redis with TTL
- Sign session cookie with API secret
apps/runtime/src/services/auth/service.rs
TokenService
Manages API tokens stored in PostgreSQL for CLI authentication. Source:apps/runtime/src/services/tokens/service.rs
Discord Integration
DiscordHandler
Serenity event handler that converts Discord gateway events to JavaScript payloads. Source:apps/runtime/src/discord_handler.rs:16
Event processing:
- Gateway event arrives from Discord
- Convert to typed payload (
expose_payloadmacro) - Serialize to JSON
- Route to guild runtime via
BotRuntime::dispatch_js_event - Filter non-guild events (flora is guild-only)
ready- Bot connectedmessageCreate- New messagemessageUpdate- Message editedmessageDelete/messageDeleteBulk- Message(s) deletedinteractionCreate- Slash commandcomponentInteraction- Button/select menumodalSubmit- Modal form submissionreactionAdd/reactionRemove/reactionRemoveAll- Reactions
apps/runtime/src/discord_handler.rs:26
Deno Core Integration
Extensions
Runtime capabilities exposed to JavaScript via Deno Core extensions. Available extensions:flora_ops- Discord operations (messages, interactions, commands)flora_kv- Key-value storageflora_cron- Cron job registrationflora_secrets- Secret accessdeno_web- Web APIs (fetch, URL, etc.)deno_fetch- HTTP clientdeno_net- Network APIsdeno_tls- TLS support
apps/runtime/src/ops/mod.rs
Ops
Operations are async Rust functions exposed to JavaScript. Example op structure:apps/runtime/src/ops/message.rs
Cron Scheduler
Per-worker cron scheduler with POSIX cron expression support. Architecture:- Shared cron registry (parking_lot::Mutex)
- Tick interval: 1 second
- Jobs evaluated using
cronercrate - Dispatched as synthetic events (
__cron:<name>)
- Register via
op_cronfrom JavaScript - Store in worker registry with next run time
- Tick checks for due jobs
- Dispatch to guild runtime with timeout
- Mark not running after completion
- Clear on guild redeploy
apps/runtime/src/runtime/worker.rs:268
HTTP API
Axum-based HTTP server for CLI integration. Endpoints:POST /deployments- Deploy guild scriptGET /deployments/:guild_id- Get deploymentGET /logs/:guild_id- Stream logs (SSE)GET /kv/:guild_id/stores- List KV storesPOST /kv/:guild_id/stores/:store/keys/:key- Set KV valuePOST /auth/login- Discord OAuthPOST /tokens- Create API token
- Timeout layer (10s)
- Logging middleware
- Auth middleware (cookie or bearer token)
apps/runtime/src/handlers/mod.rs
Worker Pool Architecture
Guild routing:- Consistent hashing (guild_id → worker index)
- Sticky routing (guilds stay on same worker)
- Migration support (move guild between workers)
- Backlog tracking per worker
Startup Sequence
Fromapps/runtime/src/main.rs:40:
- Load configuration and initialize tracing
- Connect to PostgreSQL and run migrations
- Connect to Redis with exponential backoff
- Initialize V8 once per process
- Create worker pool
- Initialize each worker sequentially (avoid V8 races)
- Load SDK bundle into all workers
- Restore cached deployments from database
- Deploy each cached guild script
- Start Discord client (Serenity)
- Start HTTP API server (Axum)
- Run both concurrently with tokio::try_join
Shutdown Sequence
Fromapps/runtime/src/runtime/mod.rs:325:
- Drop
BotRuntimetriggers shutdown - Attempt graceful migration of all guilds
- Send shutdown command to each worker
- Join worker threads
- Drop all runtime states
Guild runtimes are migrated between workers during shutdown to balance load.
Thread Safety
Arc usage:Arc<Http>- Shared Discord HTTP clientArc<BotRuntime>- Shared across handlersArc<SecretsRuntimeData>- Per-guild secret data
parking_lot::Mutexfor cron registry (fast, uncontended)tokio::Mutexfor migration queues (async-aware)Arc<RwLock<BoundedCache>>for KV DB cache
- V8 isolates are not Send/Sync
- Worker threads never share isolates
- Migration transfers ownership via channels