feat(multi-process): per-bot process isolation via PM2 + BOT_NAME#244
feat(multi-process): per-bot process isolation via PM2 + BOT_NAME#244uestney wants to merge 3 commits into
Conversation
When running multiple MetaBot instances as separate processes (e.g. via PM2 with a per-bot ecosystem entry), users may want each bot's session metadata stored under a dedicated subdirectory: ~/.metabot/<bot-name>/sessions-<bot>.json. Previously the data directory was hardcoded to SESSION_STORE_DIR or ~/.metabot. This patch adds METABOT_DATA_DIR as an additional fallback, allowing a per-bot ecosystem to set this env var without affecting other bots or the default mode. Resolution order: SESSION_STORE_DIR → METABOT_DATA_DIR → ~/.metabot Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds support for running each Feishu bot in its own Node.js process instead of
multiplexing all bots in one. Useful when:
- Restarting a single bot shouldn't disrupt others
- Bots have very different memory/CPU profiles
- Different bots need to be on different code branches/versions
Two coordinated changes:
1. src/config.ts — When BOT_NAME env var is set, loadAppConfig() filters all
four platform arrays (feishu/telegram/web/wechat) down to just the matching
bot. Throws if no bot matches. Existing single-process mode (no BOT_NAME)
is unaffected.
2. ecosystem.config.cjs — Replaces the single 'metabot' entry with one PM2
app per bot read from bots.json. Each app gets:
- BOT_NAME=<name> for filtering
- Distinct API_PORT (base + index*3) and MEMORY_PORT (base + index*3 + 1)
- METABOT_DATA_DIR=~/.metabot/<name>/ for data isolation
- MEMORY_DATABASE_DIR + META_MEMORY_URL pointing at the bot's own port
- Per-bot log files (logs/<name>-{out,error}.log)
- API_PORT_BASE configurable via .env (default 10001)
Single-process mode still works — just leave BOT_NAME unset and run with the
old ecosystem entry pattern.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds handling for an external workflow (e.g. an `mb switch <bot>` script or an
`/api/bots/:name/switch` endpoint) that wants to restart a bot pointed at a new
working directory while resuming a specific Claude session and surfacing the
last few messages back to the user.
Mechanism:
1. The external tool writes ~/.metabot/<bot>/pending-switch.json before
restarting the bot:
{ chatId?, workDir, sessionId, recentHistory: [{role, content}, ...] }
2. On startup, src/index.ts reads the file and either:
- injects sessionId immediately if chatId is known + pushes a notice card
listing the recent history, OR
- if chatId is unknown, defers the notice into bridge.pendingSwitchNotice
to be consumed by the next incoming message.
3. handleMessage() consumes pendingSwitchNotice on the first message after a
switch, injecting the sessionId before the message goes through the normal
command/query pipeline.
4. The file is unlinked after processing so the next restart is clean.
This is the missing half of a project-switch feature: ecosystem.config.cjs
already supports per-bot data dirs, but until now Claude wouldn't resume the
prior session after a workdir change, and the user got no indication that a
switch had happened.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Architecturally clean — Blocker 1: Inherits the Windows tsx wrapper bugThe new Blocker 2: Should land after #243PR #243 removes the SQLite registry. If #244 lands first, every per-bot process holds its own SQLite handle on the same Design question: default deployment modelThis rewrites the default Is that the intended default, or should multi-process be opt-in (e.g. ship Smaller things (non-blocking)
|
Summary
Three coordinated changes that together let each bot run in its own Node.js process instead of multiplexing all bots in one:
feat(session): support METABOT_DATA_DIR for per-bot data isolationsession-manager.tsreadsMETABOT_DATA_DIRenv var (falls back to~/.metabot)~/.metabot/<name>/so session files don't collidefeat(multi-process): per-bot PM2 process isolation via BOT_NAME filtersrc/config.ts— whenBOT_NAMEenv is set,loadAppConfig()filters all platform arrays (feishu/telegram/web/wechat) down to just the matching botecosystem.config.cjs— replaces the singlemetabotPM2 entry with one app per bot read frombots.json. Each gets its own port range, data dir, log filesBOT_NAMEunset)feat(bridge): handle deferred project switch via pending-switch.jsonpending-switch.jsonis dropped by the orchestrator; the target bot picks it up on next message and applies the switchWhy these go together
The three changes are strongly coupled —
METABOT_DATA_DIRis the bridge between the PM2 config and per-bot session storage; without it the multi-process setup either crashes or shares state.pending-switch.jsonis only meaningful once you have multiple processes.Compatibility
Backward-compatible: with no
BOT_NAMEenv var and the original single-app PM2 entry, behavior is identical to today.Test plan
npm run buildpassesnpm test— 219/219 real tests passbots.jsoncontaining 7 bots → confirm 7 separate processes, distinct ports