mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-21 16:05:19 +08:00
feat(cloud): configure dedicated and shared worker quotas independently
This commit is contained in:
+1
-1
@@ -71,7 +71,7 @@ dependencies = [
|
||||
"langchain-text-splitters>=1.1.2",
|
||||
"chromadb>=1.0.0,<2.0.0",
|
||||
"qdrant-client (>=1.15.1,<2.0.0)",
|
||||
"langbot-plugin==0.7.11rc3",
|
||||
"langbot-plugin==0.7.11rc4",
|
||||
"asyncpg>=0.30.0",
|
||||
"line-bot-sdk>=3.19.0",
|
||||
"matrix-nio>=0.25.2",
|
||||
|
||||
@@ -59,6 +59,9 @@ _RUNTIME_POLICY_DEFAULTS = {
|
||||
'restart_failure_window_seconds': 30.0,
|
||||
'restart_circuit_open_seconds': 60.0,
|
||||
'require_hard_limits': False,
|
||||
# Cloud-only optional overrides; null inherits the unified policy.
|
||||
'dedicated': dict.fromkeys(('max_cpus', 'max_memory_mb', 'max_pids', 'max_open_files', 'max_file_size_mb')),
|
||||
'shared': dict.fromkeys(('max_cpus', 'max_memory_mb', 'max_pids', 'max_open_files', 'max_file_size_mb')),
|
||||
},
|
||||
},
|
||||
'mcp': {'stdio': {'enabled': True}},
|
||||
|
||||
@@ -334,6 +334,24 @@ class PluginRuntimeConnector(ManagedRuntimeConnector):
|
||||
):
|
||||
if field_name in PluginWorkerPolicy.model_fields and field_name in worker:
|
||||
policy_data[field_name] = worker.get(field_name)
|
||||
if self.runtime_profile == 'shared':
|
||||
for mode in ('dedicated', 'shared'):
|
||||
overrides = worker.get(mode)
|
||||
if isinstance(overrides, dict):
|
||||
overrides = dict(overrides)
|
||||
for name, value in overrides.items():
|
||||
# Optional leaves start as null, so env loading preserves
|
||||
# strings. Parse only these trusted numeric config fields.
|
||||
if isinstance(value, str) and name in (
|
||||
'max_cpus',
|
||||
'max_memory_mb',
|
||||
'max_pids',
|
||||
'max_open_files',
|
||||
'max_file_size_mb',
|
||||
):
|
||||
overrides[name] = float(value) if name == 'max_cpus' else int(value)
|
||||
if overrides is not None:
|
||||
policy_data[mode] = overrides
|
||||
return PluginWorkerPolicy.model_validate(policy_data)
|
||||
|
||||
def _control_headers(self, *, allow_generate: bool) -> dict[str, str]:
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
from langbot.pkg.core.stages.load_config import _complete_runtime_policy_defaults, _apply_env_overrides_to_config
|
||||
from langbot.pkg.plugin.connector import PluginRuntimeConnector
|
||||
|
||||
|
||||
@pytest.mark.parametrize('mode', ['cloud', 'oss'])
|
||||
def test_mode_overrides_only_reach_cloud_runtime(mode, monkeypatch):
|
||||
monkeypatch.setenv('PLUGIN__WORKER__DEDICATED__MAX_CPUS', '0.5')
|
||||
monkeypatch.setenv('PLUGIN__WORKER__DEDICATED__MAX_MEMORY_MB', '256')
|
||||
monkeypatch.setenv('PLUGIN__WORKER__SHARED__MAX_CPUS', '1.0')
|
||||
monkeypatch.setenv('PLUGIN__WORKER__SHARED__MAX_MEMORY_MB', '512')
|
||||
config = _apply_env_overrides_to_config(_complete_runtime_policy_defaults({'plugin': {'enable': True}}))
|
||||
app = SimpleNamespace(instance_config=SimpleNamespace(data=config), deployment=SimpleNamespace(mode=mode))
|
||||
connector = PluginRuntimeConnector(app, AsyncMock())
|
||||
policy = connector._load_worker_policy()
|
||||
if mode == 'cloud':
|
||||
assert policy.dedicated.max_cpus == 0.5
|
||||
assert policy.dedicated.max_memory_mb == 256
|
||||
assert policy.shared.max_cpus == 1.0
|
||||
assert policy.shared.max_memory_mb == 512
|
||||
else:
|
||||
assert policy.dedicated is None
|
||||
assert policy.shared is None
|
||||
assert policy.max_cpus == 1.0
|
||||
assert policy.max_memory_mb == 512
|
||||
|
||||
|
||||
def test_cloud_unset_overrides_inherit_existing_limits():
|
||||
config = _complete_runtime_policy_defaults(
|
||||
{'plugin': {'enable': True, 'worker': {'max_cpus': 1.5, 'max_memory_mb': 768}}}
|
||||
)
|
||||
app = SimpleNamespace(instance_config=SimpleNamespace(data=config), deployment=SimpleNamespace(mode='cloud'))
|
||||
policy = PluginRuntimeConnector(app, AsyncMock())._load_worker_policy()
|
||||
for mode in ('dedicated', 'shared-runtime-v1'):
|
||||
resolved = policy.for_execution_mode(mode, 'shared')
|
||||
assert resolved.max_cpus == 1.5
|
||||
assert resolved.max_memory_mb == 768
|
||||
@@ -2185,7 +2185,7 @@ requires-dist = [
|
||||
{ name = "gewechat-client", specifier = ">=0.1.5" },
|
||||
{ name = "html2text", specifier = ">=2024.2.26" },
|
||||
{ name = "httpx", extras = ["socks"], specifier = ">=0.28.1" },
|
||||
{ name = "langbot-plugin", specifier = "==0.7.11rc3" },
|
||||
{ name = "langbot-plugin", specifier = "==0.7.11rc4" },
|
||||
{ name = "langchain", specifier = ">=1.3.9" },
|
||||
{ name = "langchain-core", specifier = ">=1.3.3" },
|
||||
{ name = "langchain-text-splitters", specifier = ">=1.1.2" },
|
||||
@@ -2255,7 +2255,7 @@ dev = [
|
||||
|
||||
[[package]]
|
||||
name = "langbot-plugin"
|
||||
version = "0.7.11rc3"
|
||||
version = "0.7.11rc4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiofiles" },
|
||||
@@ -2276,9 +2276,9 @@ dependencies = [
|
||||
{ name = "watchdog" },
|
||||
{ name = "websockets" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/86/bd9e90e94386d2729945242950d800ca16e969c565830338e0ae78d48daa/langbot_plugin-0.7.11rc3.tar.gz", hash = "sha256:cc8af0b97fd3b07322ecc14465a319278b00e7dbb0467034986b43a61017eaad", size = 696244, upload-time = "2026-10-12T17:19:04.321Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f4/1c/6161476312d727d7597db1be25db05bb0e55fdfb3cbf3e5814d743395164/langbot_plugin-0.7.11rc4.tar.gz", hash = "sha256:edb9b9d775b94b341ab1392a37c290f7f6b16255e20876d9dbeae6931684d0ab", size = 697204, upload-time = "2026-10-13T03:17:49.891Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/15/3c8df23a4cb6567f6ef2d26fa860eb8f88f8a5e9ea4a1c7291248ef5742e/langbot_plugin-0.7.11rc3-py3-none-any.whl", hash = "sha256:0fb60e72ba2837740796258145a1095a42866f2c27ae800154d3ce3880cc274a", size = 447347, upload-time = "2026-10-12T17:19:02.814Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/f6/73af295201ccbbace6cbcc609d3eae1c4001750c7a26b69d99e5f0783811/langbot_plugin-0.7.11rc4-py3-none-any.whl", hash = "sha256:7ed643457260b435e20d684329fdc071d0faced16c88679b2face2081258c976", size = 447841, upload-time = "2026-10-13T03:17:47.875Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user