config: make ServerArgs read-only with a single audited mutation entry (#31811)
This commit is contained in:
@@ -35,6 +35,14 @@ def make_runner(
|
||||
for name, value in arg_overrides.items():
|
||||
setattr(args, name, value)
|
||||
|
||||
# The policy routes its load-time default through the audited mutation entry
|
||||
# (server_args.override); mirror that on the stub so the write lands.
|
||||
def _override(source, **fields):
|
||||
for _field, _value in fields.items():
|
||||
setattr(args, _field, _value)
|
||||
|
||||
args.override = _override
|
||||
|
||||
return SimpleNamespace(
|
||||
server_args=args,
|
||||
model_config=SimpleNamespace(),
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
"""Context-first mutation.
|
||||
|
||||
``get_context().override(source, **fields)`` is the business mutation entry: it
|
||||
writes the resolved config bags (the single source of truth) and never touches
|
||||
``server_args`` (the pristine startup record). Routing is by NS metadata; a bad
|
||||
field aborts before any write; provenance is recorded.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from sglang.srt import runtime_context as rc
|
||||
from sglang.srt.server_args import ServerArgs
|
||||
from sglang.test.ci.ci_register import register_cpu_ci
|
||||
from sglang.test.test_utils import CustomTestCase
|
||||
|
||||
register_cpu_ci(est_time=5, suite="base-a-test-cpu")
|
||||
|
||||
|
||||
class TestContextOverride(CustomTestCase):
|
||||
def setUp(self):
|
||||
rc.reset_context()
|
||||
|
||||
def tearDown(self):
|
||||
rc.reset_context()
|
||||
|
||||
def _publish(self):
|
||||
sa = ServerArgs(model_path="dummy")
|
||||
rc.get_context().set_server_args(sa)
|
||||
return sa
|
||||
|
||||
def test_override_writes_bag_not_server_args(self):
|
||||
sa = self._publish()
|
||||
before = sa.hicache_ratio
|
||||
rc.get_context().override("test", hicache_ratio=before + 1.0)
|
||||
self.assertEqual(rc.get_memory().hicache_ratio, before + 1.0)
|
||||
# server_args stays the pristine startup record.
|
||||
self.assertEqual(sa.hicache_ratio, before)
|
||||
|
||||
def test_override_routes_across_namespaces(self):
|
||||
self._publish()
|
||||
rc.get_context().override(
|
||||
"test",
|
||||
moe_runner_backend="triton",
|
||||
page_size=64,
|
||||
disaggregation_mode="decode",
|
||||
)
|
||||
self.assertEqual(rc.get_exec().moe.moe_runner_backend, "triton")
|
||||
self.assertEqual(rc.get_schedule().page_size, 64)
|
||||
self.assertEqual(rc.get_disagg().disaggregation_mode, "decode")
|
||||
|
||||
def test_override_unknown_field_raises_and_is_atomic(self):
|
||||
self._publish()
|
||||
before = rc.get_memory().hicache_ratio
|
||||
with self.assertRaises(ValueError):
|
||||
rc.get_context().override(
|
||||
"test", hicache_ratio=before + 5.0, not_a_real_field=1
|
||||
)
|
||||
# No partial write: the valid field was not applied.
|
||||
self.assertEqual(rc.get_memory().hicache_ratio, before)
|
||||
|
||||
def test_override_before_publish_raises(self):
|
||||
with self.assertRaises(ValueError):
|
||||
rc.get_context().override("test", page_size=32)
|
||||
|
||||
def test_override_provenance_recorded(self):
|
||||
self._publish()
|
||||
rc.get_context().override("srcA", page_size=16)
|
||||
log = rc.get_context().overrides_log()
|
||||
self.assertEqual(log[-1], ("srcA", {"page_size": 16}))
|
||||
|
||||
def test_republish_resets_provenance(self):
|
||||
self._publish()
|
||||
rc.get_context().override("srcA", page_size=16)
|
||||
self.assertTrue(rc.get_context().overrides_log())
|
||||
self._publish()
|
||||
self.assertEqual(rc.get_context().overrides_log(), [])
|
||||
|
||||
def test_bare_server_args_write_raises_after_resolution(self):
|
||||
# server_args is read-only after resolution regardless of the
|
||||
# SGLANG_STRICT_CONFIG_MUTATION env; write via override instead.
|
||||
sa = ServerArgs(model_path="dummy")
|
||||
object.__setattr__(sa, "_declarations_materialized", True)
|
||||
with self.assertRaises(AttributeError):
|
||||
sa.page_size = 999
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user