mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
Moved monitoring of last_execution_time to system_stats (#9851)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
parent
38ffc85470
commit
e045b757fa
@ -72,7 +72,10 @@ from openhands.runtime.utils.bash import BashSession
|
||||
from openhands.runtime.utils.files import insert_lines, read_lines
|
||||
from openhands.runtime.utils.memory_monitor import MemoryMonitor
|
||||
from openhands.runtime.utils.runtime_init import init_user_and_working_directory
|
||||
from openhands.runtime.utils.system_stats import get_system_stats
|
||||
from openhands.runtime.utils.system_stats import (
|
||||
get_system_stats,
|
||||
update_last_execution_time,
|
||||
)
|
||||
from openhands.utils.async_utils import call_sync_from_async, wait_all
|
||||
|
||||
if sys.platform == 'win32':
|
||||
@ -844,6 +847,8 @@ if __name__ == '__main__':
|
||||
status_code=500,
|
||||
detail=traceback.format_exc(),
|
||||
)
|
||||
finally:
|
||||
update_last_execution_time()
|
||||
|
||||
@app.post('/update_mcp_server')
|
||||
async def update_mcp_server(request: Request):
|
||||
|
||||
@ -46,6 +46,7 @@ from openhands.integrations.provider import PROVIDER_TOKEN_TYPE
|
||||
from openhands.runtime.base import Runtime
|
||||
from openhands.runtime.plugins import PluginRequirement
|
||||
from openhands.runtime.utils.request import send_request
|
||||
from openhands.runtime.utils.system_stats import update_last_execution_time
|
||||
from openhands.utils.http_session import HttpSession
|
||||
from openhands.utils.tenacity_stop import stop_if_should_exit
|
||||
|
||||
@ -328,6 +329,8 @@ class ActionExecutionClient(Runtime):
|
||||
raise AgentRuntimeTimeoutError(
|
||||
f'Runtime failed to return execute_action before the requested timeout of {action.timeout}s'
|
||||
)
|
||||
finally:
|
||||
update_last_execution_time()
|
||||
return obs
|
||||
|
||||
def run(self, action: CmdRunAction) -> Observation:
|
||||
|
||||
@ -4,6 +4,25 @@ import time
|
||||
|
||||
import psutil
|
||||
|
||||
_start_time = time.time()
|
||||
_last_execution_time = time.time()
|
||||
|
||||
|
||||
def get_system_info() -> dict[str, object]:
|
||||
current_time = time.time()
|
||||
uptime = current_time - _start_time
|
||||
idle_time = current_time - _last_execution_time
|
||||
return {
|
||||
'uptime': uptime,
|
||||
'idle_time': idle_time,
|
||||
'resources': get_system_stats(),
|
||||
}
|
||||
|
||||
|
||||
def update_last_execution_time():
|
||||
global _last_execution_time
|
||||
_last_execution_time = time.time()
|
||||
|
||||
|
||||
def get_system_stats() -> dict[str, object]:
|
||||
"""Get current system resource statistics.
|
||||
|
||||
@ -1,11 +1,6 @@
|
||||
import time
|
||||
from fastapi import FastAPI
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
|
||||
from openhands.runtime.utils.system_stats import get_system_stats
|
||||
|
||||
start_time = time.time()
|
||||
last_execution_time = start_time
|
||||
from openhands.runtime.utils.system_stats import get_system_info
|
||||
|
||||
|
||||
def add_health_endpoints(app: FastAPI):
|
||||
@ -19,20 +14,4 @@ def add_health_endpoints(app: FastAPI):
|
||||
|
||||
@app.get('/server_info')
|
||||
async def get_server_info():
|
||||
current_time = time.time()
|
||||
uptime = current_time - start_time
|
||||
idle_time = current_time - last_execution_time
|
||||
|
||||
response = {
|
||||
'uptime': uptime,
|
||||
'idle_time': idle_time,
|
||||
'resources': get_system_stats(),
|
||||
}
|
||||
return response
|
||||
|
||||
@app.middleware('http')
|
||||
async def update_last_execution_time(request: Request, call_next):
|
||||
global last_execution_time
|
||||
response = await call_next(request)
|
||||
last_execution_time = time.time()
|
||||
return response
|
||||
return get_system_info()
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
"""Tests for system stats utilities."""
|
||||
|
||||
import time
|
||||
from unittest.mock import patch
|
||||
|
||||
import psutil
|
||||
|
||||
from openhands.runtime.utils.system_stats import get_system_stats
|
||||
from openhands.runtime.utils.system_stats import (
|
||||
get_system_info,
|
||||
get_system_stats,
|
||||
update_last_execution_time,
|
||||
)
|
||||
|
||||
|
||||
def test_get_system_stats():
|
||||
@ -58,3 +65,96 @@ def test_get_system_stats_stability():
|
||||
stats = get_system_stats()
|
||||
assert isinstance(stats, dict)
|
||||
assert stats['cpu_percent'] >= 0
|
||||
|
||||
|
||||
def test_get_system_info():
|
||||
"""Test that get_system_info returns valid system information."""
|
||||
with patch(
|
||||
'openhands.runtime.utils.system_stats.get_system_stats'
|
||||
) as mock_get_stats:
|
||||
mock_get_stats.return_value = {'cpu_percent': 10.0}
|
||||
|
||||
info = get_system_info()
|
||||
|
||||
# Test structure
|
||||
assert isinstance(info, dict)
|
||||
assert set(info.keys()) == {'uptime', 'idle_time', 'resources'}
|
||||
|
||||
# Test values
|
||||
assert isinstance(info['uptime'], float)
|
||||
assert isinstance(info['idle_time'], float)
|
||||
assert info['uptime'] > 0
|
||||
assert info['idle_time'] >= 0
|
||||
assert info['resources'] == {'cpu_percent': 10.0}
|
||||
|
||||
# Verify get_system_stats was called
|
||||
mock_get_stats.assert_called_once()
|
||||
|
||||
|
||||
def test_update_last_execution_time():
|
||||
"""Test that update_last_execution_time updates the last execution time."""
|
||||
# Get initial system info
|
||||
initial_info = get_system_info()
|
||||
initial_idle_time = initial_info['idle_time']
|
||||
|
||||
# Wait a bit to ensure time difference
|
||||
time.sleep(0.1)
|
||||
|
||||
# Update last execution time
|
||||
update_last_execution_time()
|
||||
|
||||
# Get updated system info
|
||||
updated_info = get_system_info()
|
||||
updated_idle_time = updated_info['idle_time']
|
||||
|
||||
# The idle time should be reset (close to zero)
|
||||
assert updated_idle_time < initial_idle_time
|
||||
assert updated_idle_time < 0.1 # Should be very small
|
||||
|
||||
|
||||
def test_idle_time_increases_without_updates():
|
||||
"""Test that idle_time increases when no updates are made."""
|
||||
# Update last execution time to reset idle time
|
||||
update_last_execution_time()
|
||||
|
||||
# Get initial system info
|
||||
initial_info = get_system_info()
|
||||
initial_idle_time = initial_info['idle_time']
|
||||
|
||||
# Wait a bit
|
||||
time.sleep(0.2)
|
||||
|
||||
# Get updated system info without calling update_last_execution_time
|
||||
updated_info = get_system_info()
|
||||
updated_idle_time = updated_info['idle_time']
|
||||
|
||||
# The idle time should have increased
|
||||
assert updated_idle_time > initial_idle_time
|
||||
assert updated_idle_time >= 0.2 # Should be at least the sleep time
|
||||
|
||||
|
||||
@patch('time.time')
|
||||
def test_idle_time_calculation(mock_time):
|
||||
"""Test that idle_time is calculated correctly."""
|
||||
# Mock time.time() to return controlled values
|
||||
mock_time.side_effect = [
|
||||
100.0, # Initial _start_time
|
||||
100.0, # Initial _last_execution_time
|
||||
110.0, # Current time in get_system_info
|
||||
]
|
||||
|
||||
# Import the module again to reset the global variables with our mocked time
|
||||
import importlib
|
||||
|
||||
import openhands.runtime.utils.system_stats
|
||||
|
||||
importlib.reload(openhands.runtime.utils.system_stats)
|
||||
|
||||
# Get system info
|
||||
from openhands.runtime.utils.system_stats import get_system_info
|
||||
|
||||
info = get_system_info()
|
||||
|
||||
# Verify idle_time calculation
|
||||
assert info['uptime'] == 10.0 # 110 - 100
|
||||
assert info['idle_time'] == 10.0 # 110 - 100
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user