[Frontend] Configurable video storage backends with TTL (#2531)
Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>
This commit is contained in:
1 parent
7e152ca64b
commit
951ae28eb0
12 files changed
+531
-66
No files matched your search
@@ -1020,6 +1020,31 @@ def test_invalid_lora_returns_400(test_client):
|
||||
assert "lora object" in failed["error"]["message"].lower()
|
||||
|
||||
|
||||
def test_failed_generation_awaits_storage_cleanup(test_client, isolated_video_backends, mocker: MockerFixture):
|
||||
"""Regression (merge seam): when async generation raises, the failure handler
|
||||
must ``await _cleanup_video(video_id)`` (single-arg, async) and still record
|
||||
FAILED. Upstream carried a sync ``_cleanup_video(video_id, output_path)`` whose
|
||||
stale call in the generic handler sat outside the conflict markers; against the
|
||||
PR's async storage manager that raised NameError before the FAILED update,
|
||||
wedging the job in IN_PROGRESS and orphaning the artifact."""
|
||||
_store, _tasks, storage = isolated_video_backends
|
||||
delete_spy = mocker.spy(storage, "delete")
|
||||
mocker.patch.object(
|
||||
OmniOpenAIServingVideo,
|
||||
"generate_video_bytes",
|
||||
side_effect=RuntimeError("GPU exploded"),
|
||||
)
|
||||
|
||||
response = test_client.post("/v1/videos", data={"prompt": "will fail"})
|
||||
assert response.status_code == 200
|
||||
video_id = response.json()["id"]
|
||||
|
||||
failed = _wait_for_status(test_client, video_id, VideoGenerationStatus.FAILED.value)
|
||||
assert failed["error"]["code"] == 500
|
||||
assert "GPU exploded" in failed["error"]["message"]
|
||||
delete_spy.assert_called_once_with(video_id)
|
||||
|
||||
|
||||
def test_async_guardrail_error_returns_400_on_retrieve(test_client, mocker: MockerFixture):
|
||||
mocker.patch.object(
|
||||
OmniOpenAIServingVideo,
|
||||
@@ -1178,7 +1203,7 @@ def test_delete_completed_job_removes_file_and_metadata(test_client, mocker: Moc
|
||||
final = _wait_for_status(test_client, video_id, VideoGenerationStatus.COMPLETED.value)
|
||||
file_name = final["file_name"]
|
||||
assert file_name is not None
|
||||
file_path = os.path.join(api_server.STORAGE_MANAGER.storage_path, file_name)
|
||||
file_path = os.path.join(api_server.STORAGE_MANAGER.storage_path, video_id)
|
||||
assert os.path.exists(file_path)
|
||||
|
||||
delete_resp = test_client.delete(f"/v1/videos/{video_id}")
|
||||
@@ -1189,6 +1214,30 @@ def test_delete_completed_job_removes_file_and_metadata(test_client, mocker: Moc
|
||||
assert not os.path.exists(file_path)
|
||||
|
||||
|
||||
def test_download_completed_job_uses_storage_open_and_download_name(test_client, mocker: MockerFixture):
|
||||
video_bytes = b"stored-video-data"
|
||||
mocker.patch(
|
||||
"vllm_omni.entrypoints.openai.serving_video._encode_video_bytes",
|
||||
return_value=video_bytes,
|
||||
)
|
||||
create_resp = test_client.post("/v1/videos", data={"prompt": "Download this video"})
|
||||
assert create_resp.status_code == 200
|
||||
video_id = create_resp.json()["id"]
|
||||
|
||||
final = _wait_for_status(test_client, video_id, VideoGenerationStatus.COMPLETED.value)
|
||||
file_name = final["file_name"]
|
||||
assert file_name == f"{video_id}.mp4"
|
||||
|
||||
storage_path = os.path.join(api_server.STORAGE_MANAGER.storage_path, video_id)
|
||||
assert os.path.exists(storage_path)
|
||||
|
||||
response = test_client.get(f"/v1/videos/{video_id}/content")
|
||||
assert response.status_code == 200
|
||||
assert response.content == video_bytes
|
||||
assert response.headers["content-type"] == "video/mp4"
|
||||
assert file_name in response.headers["content-disposition"]
|
||||
|
||||
|
||||
def test_delete_in_progress_job_cancels_task_and_removes_metadata(test_client):
|
||||
handler = BlockingVideoHandler()
|
||||
test_client.app.state.openai_serving_video = handler
|
||||
|
||||
Reference in new issue
Block a user