mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 21:26:39 +00:00
fix(sandbox): reject non-finite health_check_skip_seconds in config (#5997)
`health_check_skip_seconds` was the only float field in SandboxConfig without `allow_inf_nan=False`, and `ge=0` alone does not stop inf (`inf >= 0` is true). A config.yaml value of `1e999` loads as the string "1e999" and pydantic's float coercion turns it into inf, so the field accepted it and the BoxLite warm-reuse site then skipped the health check permanently: `skip_seconds > 0 and (time.time() - released_at) < skip_seconds` holds forever for inf, so every box this instance recently released is promoted without validation instead of failing fast at config load. Add `allow_inf_nan=False`, matching the sibling sandbox float fields (`bash_command_timeout`, `renewal_interval_seconds`, `ttl_multiplier`) and the ownership lease-TTL model validator. Red/green: `test_sandbox_config_rejects_non_finite_health_check_skip_seconds` parametrizes inf and "1e999"; both were accepted before the fix (RED) and are rejected after. Full boxlite suite: 54 passed / 15 skipped. Regression: the sandbox/config/ownership subset fails 17 tests on this Windows host both with and without the change, with a byte-identical failure-name set (environment-type: process-spawn and file-stat behavior), so no regressions are introduced. Signed-off-by: yetuge <2219677952@qq.com>
This commit is contained in:
parent
5850b0da9f
commit
160fd50a28
@ -236,6 +236,7 @@ class SandboxConfig(BaseModel):
|
||||
health_check_skip_seconds: float | None = Field(
|
||||
default=None,
|
||||
ge=0,
|
||||
allow_inf_nan=False,
|
||||
description="BoxLite-only reclaim skip window in seconds for boxes recently released by this provider instance. Set to 0 to always validate before warm reuse.",
|
||||
)
|
||||
ownership: SandboxOwnershipConfig | None = Field(
|
||||
|
||||
@ -18,9 +18,11 @@ import time
|
||||
import types
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from deerflow.community.boxlite.box import BoxliteBox
|
||||
from deerflow.community.boxlite.provider import BoxliteProvider, _import_simplebox
|
||||
from deerflow.config.sandbox_config import SandboxConfig
|
||||
from deerflow.trace_context import get_current_trace_id, request_trace_context
|
||||
|
||||
_LEGACY_COLLIDING_IDENTITIES = (
|
||||
@ -543,6 +545,25 @@ async def test_acquire_async_propagates_request_trace_context(monkeypatch):
|
||||
await asyncio.to_thread(provider.shutdown)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [float("inf"), "1e999"])
|
||||
def test_sandbox_config_rejects_non_finite_health_check_skip_seconds(value):
|
||||
"""`ge=0` alone lets a non-finite skip window through.
|
||||
|
||||
`health_check_skip_seconds: 1e999` in config.yaml loads as the string
|
||||
"1e999" and pydantic's float coercion turns it into inf; `ge=0` accepts
|
||||
inf (inf >= 0). At the warm-reuse site the check `skip_seconds > 0 and
|
||||
(now - released_at) < skip_seconds` then holds forever, so recently
|
||||
released boxes are promoted without the health check permanently instead
|
||||
of failing fast at config load. `allow_inf_nan=False` (as already set on
|
||||
the sibling sandbox float fields) makes the config layer reject it.
|
||||
"""
|
||||
with pytest.raises(ValidationError):
|
||||
SandboxConfig(
|
||||
use="deerflow.community.boxlite.provider:BoxliteProvider",
|
||||
health_check_skip_seconds=value,
|
||||
)
|
||||
|
||||
|
||||
def test_explicit_recent_reclaim_skip_avoids_health_check(monkeypatch):
|
||||
"""A configured skip window can reclaim recently released boxes without a ping."""
|
||||
monkeypatch.setattr(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user