feat(cloud): harden multi-tenant runtime resources

This commit is contained in:
Junyan Qin
2026-07-29 11:32:26 +08:00
parent 32abbb636f
commit ae85ac2b16
211 changed files with 14963 additions and 1968 deletions
+14 -2
View File
@@ -17,6 +17,10 @@ services:
# Shared with the langbot service and sent only as a WebSocket handshake
# header. Generate with: openssl rand -hex 32
- LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN=${LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN:-}
# Process-wide admission for every asyncio.to_thread() call.
- LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS=${LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS:-8}
- LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING=${LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING:-128}
- LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE=${LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE:-4}
command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "rt"]
networks:
- langbot_network
@@ -49,10 +53,13 @@ services:
# An empty value is accepted by Compose so Box can remain optional, but
# the Box runtime itself fails closed when the profile is started.
- LANGBOT_BOX_CONTROL_TOKEN=${LANGBOT_BOX_CONTROL_TOKEN:-}
# Box has its own process-wide blocking-work budget.
- LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS=${LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS:-8}
- LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING=${LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING:-128}
- LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE=${LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE:-4}
# The Box runtime does NOT read box.local.* from config.yaml or env; it
# receives its functional configuration from LangBot via the INIT RPC
# action. LANGBOT_BOX_CONTROL_TOKEN is the intentional security-only
# exception; do not add BOX__* here because those would be ignored.
# action. Do not add BOX__* here because those would be ignored.
# Launched through the same CLI entry point as the plugin runtime
# (`langbot_plugin.cli.__init__ <subcommand>`). WebSocket is the default
# control transport — mirrors `rt`, which also runs with no flag. Pass
@@ -76,6 +83,11 @@ services:
# Must match the value supplied to langbot_box. The token is sent only
# in WebSocket handshake headers, never in URLs or action payloads.
- LANGBOT_BOX_CONTROL_TOKEN=${LANGBOT_BOX_CONTROL_TOKEN:-}
# Core process-wide blocking-work admission. These are native config
# overrides and are persisted with the effective data/config.yaml.
- SYSTEM__BLOCKING_EXECUTOR__MAX_WORKERS=${LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS:-8}
- SYSTEM__BLOCKING_EXECUTOR__MAX_PENDING=${LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING:-128}
- SYSTEM__BLOCKING_EXECUTOR__MAX_INFLIGHT_PER_SCOPE=${LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE:-4}
# Unified env-override convention: SECTION__SUBSECTION__KEY overrides the
# matching config.yaml field (see LoadConfigStage). These map onto
# box.* and are forwarded to the Box runtime via INIT RPC.
+56 -4
View File
@@ -91,6 +91,12 @@ metadata:
data:
TZ: "Asia/Shanghai"
PLUGIN__RUNTIME_WS_URL: "ws://langbot-plugin-runtime:5400/control/ws"
SYSTEM__BLOCKING_EXECUTOR__MAX_WORKERS: "8"
SYSTEM__BLOCKING_EXECUTOR__MAX_PENDING: "128"
SYSTEM__BLOCKING_EXECUTOR__MAX_INFLIGHT_PER_SCOPE: "4"
LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS: "8"
LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING: "128"
LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE: "4"
# Box sandbox runtime endpoint. LangBot connects to the Box runtime over
# WebSocket. The hostname MUST match the langbot-box Service name. Note the
# in-container default ("langbot_box") uses an underscore, which is an
@@ -136,6 +142,21 @@ spec:
secretKeyRef:
name: langbot-plugin-runtime-control
key: token
- name: LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS
valueFrom:
configMapKeyRef:
name: langbot-config
key: LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS
- name: LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING
valueFrom:
configMapKeyRef:
name: langbot-config
key: LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING
- name: LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE
valueFrom:
configMapKeyRef:
name: langbot-config
key: LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE
volumeMounts:
- name: plugin-data
mountPath: /app/data/plugins
@@ -262,9 +283,23 @@ spec:
secretKeyRef:
name: langbot-box-control
key: token
- name: LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS
valueFrom:
configMapKeyRef:
name: langbot-config
key: LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS
- name: LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING
valueFrom:
configMapKeyRef:
name: langbot-config
key: LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING
- name: LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE
valueFrom:
configMapKeyRef:
name: langbot-config
key: LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE
# The Box runtime does NOT read box.local.* / BOX__* from its own env;
# it receives its functional configuration from LangBot via INIT.
# LANGBOT_BOX_CONTROL_TOKEN is the security-only exception.
volumeMounts:
# Box workspace root — identical path on node, box, and sandbox
# containers (see the IMPORTANT note above).
@@ -290,7 +325,9 @@ spec:
failureThreshold: 3
readinessProbe:
httpGet:
path: /healthz
# Unlike liveness, readiness validates the configured backend and
# all strict managed-mode isolation guarantees.
path: /readyz
port: 5410
initialDelaySeconds: 10
periodSeconds: 5
@@ -379,6 +416,21 @@ spec:
secretKeyRef:
name: langbot-plugin-runtime-control
key: token
- name: SYSTEM__BLOCKING_EXECUTOR__MAX_WORKERS
valueFrom:
configMapKeyRef:
name: langbot-config
key: SYSTEM__BLOCKING_EXECUTOR__MAX_WORKERS
- name: SYSTEM__BLOCKING_EXECUTOR__MAX_PENDING
valueFrom:
configMapKeyRef:
name: langbot-config
key: SYSTEM__BLOCKING_EXECUTOR__MAX_PENDING
- name: SYSTEM__BLOCKING_EXECUTOR__MAX_INFLIGHT_PER_SCOPE
valueFrom:
configMapKeyRef:
name: langbot-config
key: SYSTEM__BLOCKING_EXECUTOR__MAX_INFLIGHT_PER_SCOPE
# Box (sandbox) runtime endpoint. Connects LangBot to the langbot-box
# Service over WebSocket. Remove this (and the langbot-box Deployment)
# and set BOX__ENABLED=false if you do not want the sandbox.
@@ -426,7 +478,7 @@ spec:
# Liveness probe to restart container if it becomes unresponsive
livenessProbe:
httpGet:
path: /
path: /healthz
port: 5300
initialDelaySeconds: 60
periodSeconds: 10
@@ -435,7 +487,7 @@ spec:
# Readiness probe to know when container is ready to accept traffic
readinessProbe:
httpGet:
path: /
path: /healthz
port: 5300
initialDelaySeconds: 30
periodSeconds: 5