mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
fix: Use _send_action_server_request in send_action_for_execution (#5951)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
parent
5ca0beadfb
commit
411b63159f
@ -249,8 +249,7 @@ class ActionExecutionClient(Runtime):
|
||||
assert action.timeout is not None
|
||||
|
||||
try:
|
||||
with send_request(
|
||||
self.session,
|
||||
with self._send_action_server_request(
|
||||
'POST',
|
||||
f'{self._get_action_execution_server_host()}/execute_action',
|
||||
json={'action': event_to_dict(action)},
|
||||
|
||||
@ -329,9 +329,14 @@ class RemoteRuntime(ActionExecutionClient):
|
||||
elif pod_status in ('failed', 'unknown', 'crashloopbackoff'):
|
||||
# clean up the runtime
|
||||
self.close()
|
||||
raise AgentRuntimeUnavailableError(
|
||||
f'Runtime (ID={self.runtime_id}) failed to start. Current status: {pod_status}. Pod Logs:\n{runtime_data.get("pod_logs", "N/A")}'
|
||||
)
|
||||
if pod_status == 'crashloopbackoff':
|
||||
raise AgentRuntimeUnavailableError(
|
||||
'Runtime crashed and is being restarted, potentially due to memory usage. Please try again.'
|
||||
)
|
||||
else:
|
||||
raise AgentRuntimeUnavailableError(
|
||||
f'Runtime is unavailable (status: {pod_status}). Please try again.'
|
||||
)
|
||||
else:
|
||||
# Maybe this should be a hard failure, but passing through in case the API changes
|
||||
self.log('warning', f'Unknown pod status: {pod_status}')
|
||||
@ -371,15 +376,17 @@ class RemoteRuntime(ActionExecutionClient):
|
||||
f'No response received within the timeout period for url: {url}',
|
||||
)
|
||||
raise
|
||||
|
||||
except requests.HTTPError as e:
|
||||
if e.response.status_code == 404:
|
||||
raise AgentRuntimeNotFoundError(
|
||||
'Runtime unavailable: System resources may be exhausted due to running commands. This may be fixed by retrying.'
|
||||
) from e
|
||||
elif e.response.status_code == 502:
|
||||
raise AgentRuntimeDisconnectedError(
|
||||
'Runtime disconnected: System resources may be exhausted due to running commands. This may be fixed by retrying.'
|
||||
) from e
|
||||
if e.response.status_code in (404, 502):
|
||||
if e.response.status_code == 404:
|
||||
raise AgentRuntimeDisconnectedError(
|
||||
'Runtime is not responding. This may be temporary, please try again.'
|
||||
) from e
|
||||
else: # 502
|
||||
raise AgentRuntimeDisconnectedError(
|
||||
'Runtime is temporarily unavailable. This may be due to a restart or network issue, please try again.'
|
||||
) from e
|
||||
elif e.response.status_code == 503:
|
||||
self.log('warning', 'Runtime appears to be paused. Resuming...')
|
||||
self._resume_runtime()
|
||||
|
||||
87
tests/unit/test_runtime_reboot.py
Normal file
87
tests/unit/test_runtime_reboot.py
Normal file
@ -0,0 +1,87 @@
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from openhands.core.exceptions import (
|
||||
AgentRuntimeDisconnectedError,
|
||||
AgentRuntimeTimeoutError,
|
||||
)
|
||||
from openhands.events.action import CmdRunAction
|
||||
from openhands.runtime.base import Runtime
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_session():
|
||||
return Mock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def runtime(mock_session):
|
||||
runtime = Mock(spec=Runtime)
|
||||
runtime.session = mock_session
|
||||
runtime.send_action_for_execution = Mock()
|
||||
return runtime
|
||||
|
||||
|
||||
def test_runtime_timeout_error(runtime, mock_session):
|
||||
# Create a command action
|
||||
action = CmdRunAction(command='test command')
|
||||
action.timeout = 120
|
||||
|
||||
# Mock the runtime to raise a timeout error
|
||||
runtime.send_action_for_execution.side_effect = AgentRuntimeTimeoutError(
|
||||
'Runtime failed to return execute_action before the requested timeout of 120s'
|
||||
)
|
||||
|
||||
# Verify that the error message indicates a timeout
|
||||
with pytest.raises(AgentRuntimeTimeoutError) as exc_info:
|
||||
runtime.send_action_for_execution(action)
|
||||
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== 'Runtime failed to return execute_action before the requested timeout of 120s'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'status_code,expected_message',
|
||||
[
|
||||
(404, 'Runtime is not responding. This may be temporary, please try again.'),
|
||||
(
|
||||
502,
|
||||
'Runtime is temporarily unavailable. This may be due to a restart or network issue, please try again.',
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_runtime_disconnected_error(
|
||||
runtime, mock_session, status_code, expected_message
|
||||
):
|
||||
# Mock the request to return the specified status code
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = status_code
|
||||
mock_response.raise_for_status = Mock(
|
||||
side_effect=requests.HTTPError(response=mock_response)
|
||||
)
|
||||
mock_response.json = Mock(
|
||||
return_value={
|
||||
'observation': 'run',
|
||||
'content': 'test',
|
||||
'extras': {'command_id': 'test_id', 'command': 'test command'},
|
||||
}
|
||||
)
|
||||
|
||||
# Mock the runtime to raise the error
|
||||
runtime.send_action_for_execution.side_effect = AgentRuntimeDisconnectedError(
|
||||
expected_message
|
||||
)
|
||||
|
||||
# Create a command action
|
||||
action = CmdRunAction(command='test command')
|
||||
action.timeout = 120
|
||||
|
||||
# Verify that the error message is correct
|
||||
with pytest.raises(AgentRuntimeDisconnectedError) as exc_info:
|
||||
runtime.send_action_for_execution(action)
|
||||
|
||||
assert str(exc_info.value) == expected_message
|
||||
Loading…
x
Reference in New Issue
Block a user