Skip to content

Commit 39c3f6f

Browse files
committed
Fix 500 errors when requesting file logs
1 parent 4b3ff66 commit 39c3f6f

File tree

2 files changed

+13
-46
lines changed

2 files changed

+13
-46
lines changed

src/dstack/_internal/server/services/logs/filelog.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import List, Union
33
from uuid import UUID
44

5+
from dstack._internal.core.errors import ServerClientError
56
from dstack._internal.core.models.logs import (
67
JobSubmissionLogs,
78
LogEvent,
@@ -14,7 +15,6 @@
1415
from dstack._internal.server.schemas.runner import LogEvent as RunnerLogEvent
1516
from dstack._internal.server.services.logs.base import (
1617
LogStorage,
17-
LogStorageError,
1818
b64encode_raw_message,
1919
unix_time_ms_to_datetime,
2020
)
@@ -30,9 +30,6 @@ def __init__(self, root: Union[Path, str, None] = None) -> None:
3030
self.root = Path(root)
3131

3232
def poll_logs(self, project: ProjectModel, request: PollLogsRequest) -> JobSubmissionLogs:
33-
if request.descending:
34-
raise LogStorageError("descending: true is not supported")
35-
3633
log_producer = LogProducer.RUNNER if request.diagnose else LogProducer.JOB
3734
log_file_path = self._get_log_file_path(
3835
project_name=project.name,
@@ -46,11 +43,11 @@ def poll_logs(self, project: ProjectModel, request: PollLogsRequest) -> JobSubmi
4643
try:
4744
start_line = int(request.next_token)
4845
if start_line < 0:
49-
raise LogStorageError(
46+
raise ServerClientError(
5047
f"Invalid next_token: {request.next_token}. Must be a non-negative integer."
5148
)
5249
except ValueError:
53-
raise LogStorageError(
50+
raise ServerClientError(
5451
f"Invalid next_token: {request.next_token}. Must be a valid integer."
5552
)
5653

@@ -59,9 +56,12 @@ def poll_logs(self, project: ProjectModel, request: PollLogsRequest) -> JobSubmi
5956
current_line = 0
6057

6158
try:
59+
# FIXME: Do not read all the lines in memory
6260
with open(log_file_path) as f:
6361
lines = f.readlines()
64-
62+
except FileNotFoundError:
63+
pass
64+
else:
6565
for i, line in enumerate(lines):
6666
if current_line < start_line:
6767
current_line += 1
@@ -83,9 +83,6 @@ def poll_logs(self, project: ProjectModel, request: PollLogsRequest) -> JobSubmi
8383
next_token = str(current_line)
8484
break
8585

86-
except IOError as e:
87-
raise LogStorageError(f"Failed to read log file {log_file_path}: {e}")
88-
8986
return JobSubmissionLogs(logs=logs, next_token=next_token)
9087

9188
def write_logs(

src/tests/_internal/server/services/test_logs.py

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from pydantic import ValidationError
1414
from sqlalchemy.ext.asyncio import AsyncSession
1515

16+
from dstack._internal.core.errors import ServerClientError
1617
from dstack._internal.core.models.logs import LogEvent, LogEventSource
1718
from dstack._internal.server.models import ProjectModel
1819
from dstack._internal.server.schemas.logs import PollLogsRequest
@@ -206,49 +207,22 @@ async def test_poll_logs_invalid_next_token_raises_error(
206207
limit=10,
207208
diagnose=True,
208209
)
209-
with pytest.raises(
210-
LogStorageError, match="Invalid next_token: invalid. Must be a valid integer."
211-
):
210+
with pytest.raises(ServerClientError):
212211
log_storage.poll_logs(project, poll_request)
213212

214213
# Test with negative next_token
215214
poll_request.next_token = "-1"
216-
with pytest.raises(
217-
LogStorageError, match="Invalid next_token: -1. Must be a non-negative integer."
218-
):
215+
with pytest.raises(ServerClientError):
219216
log_storage.poll_logs(project, poll_request)
220217

221218
# Test with float next_token
222219
poll_request.next_token = "1.5"
223-
with pytest.raises(
224-
LogStorageError, match="Invalid next_token: 1.5. Must be a valid integer."
225-
):
220+
with pytest.raises(ServerClientError):
226221
log_storage.poll_logs(project, poll_request)
227222

228223
@pytest.mark.asyncio
229224
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
230-
async def test_poll_logs_descending_raises_error(
231-
self, test_db, session: AsyncSession, tmp_path: Path
232-
):
233-
project = await create_project(session=session)
234-
log_storage = FileLogStorage(tmp_path)
235-
236-
# Test that descending=True raises LogStorageError
237-
poll_request = PollLogsRequest(
238-
run_name="test_run",
239-
job_submission_id=UUID("1b0e1b45-2f8c-4ab6-8010-a0d1a3e44e0e"),
240-
limit=10,
241-
diagnose=True,
242-
# Note: This bypasses schema validation for testing the implementation
243-
)
244-
poll_request.descending = True # Set directly to bypass validation
245-
246-
with pytest.raises(LogStorageError, match="descending: true is not supported"):
247-
log_storage.poll_logs(project, poll_request)
248-
249-
@pytest.mark.asyncio
250-
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
251-
async def test_poll_logs_file_not_found_raises_error(
225+
async def test_poll_logs_file_not_found_raises_no_error(
252226
self, test_db, session: AsyncSession, tmp_path: Path
253227
):
254228
project = await create_project(session=session)
@@ -261,11 +235,7 @@ async def test_poll_logs_file_not_found_raises_error(
261235
limit=10,
262236
diagnose=True,
263237
)
264-
265-
with pytest.raises(
266-
LogStorageError, match="Failed to read log file .* No such file or directory"
267-
):
268-
log_storage.poll_logs(project, poll_request)
238+
log_storage.poll_logs(project, poll_request)
269239

270240
@pytest.mark.asyncio
271241
@pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)

0 commit comments

Comments
 (0)