77from datetime import datetime , timedelta , timezone
88from typing import Any
99
10- from fastapi import APIRouter , Query , Request
10+ from fastapi import APIRouter , BackgroundTasks , Query , Request
1111from fastapi .responses import RedirectResponse
1212
1313from app .core .errors import ApiError , ErrorCode
@@ -109,6 +109,7 @@ def _quality_score(image: Any, *, weights: dict[str, float] | None = None) -> fl
109109@router .get ("/random" )
110110async def random_image (
111111 request : Request ,
112+ background_tasks : BackgroundTasks ,
112113 format : str = "image" ,
113114 redirect : int = 0 ,
114115 attempts : int | None = None ,
@@ -350,15 +351,9 @@ def _no_match_error() -> ApiError:
350351 use_pixiv_cat = bool (runtime .image_proxy_use_pixiv_cat ) or int (pixiv_cat ) == 1
351352 mirror_host = mirror_host_override or str (getattr (runtime , "image_proxy_pximg_mirror_host" , "" ) or "" ).strip () or "i.pixiv.cat"
352353
353- def _spawn_best_effort (coro ) -> None :
354- async def _run () -> None :
355- try :
356- await coro
357- except Exception :
358- pass
359-
354+ async def _best_effort (fn , * args , timeout_s : float = 1.5 , ** kwargs ) -> None : # type: ignore[no-untyped-def]
360355 try :
361- asyncio .create_task ( _run ( ))
356+ await asyncio .wait_for ( fn ( * args , ** kwargs ), timeout = float ( timeout_s ))
362357 except Exception :
363358 pass
364359
@@ -713,10 +708,14 @@ def _needs_opportunistic_hydrate(image: Any) -> bool:
713708 tags = await get_tag_names_for_image (session , image_id = image .id )
714709
715710 if _needs_opportunistic_hydrate (image ):
716- try :
717- await enqueue_opportunistic_hydrate_metadata (engine , illust_id = int (image .illust_id ), reason = "random" )
718- except Exception :
719- pass
711+ background_tasks .add_task (
712+ _best_effort ,
713+ enqueue_opportunistic_hydrate_metadata ,
714+ engine ,
715+ illust_id = int (image .illust_id ),
716+ reason = "random" ,
717+ timeout_s = 2.5 ,
718+ )
720719
721720 if format == "image" and redirect == 1 :
722721 qp : list [tuple [str , str ]] = []
@@ -725,11 +724,17 @@ def _needs_opportunistic_hydrate(image: Any) -> bool:
725724 if mirror_host_override is not None :
726725 qp .append (("pximg_mirror_host" , str (mirror_host_override )))
727726 qs = ("?" + "&" .join ([f"{ k } ={ v } " for k , v in qp ])) if qp else ""
728- return RedirectResponse (
727+ resp = RedirectResponse (
729728 url = f"/i/{ image .id } .{ image .ext } { qs } " ,
730729 status_code = 302 ,
731730 headers = {"Cache-Control" : "no-store" },
732731 )
732+ try :
733+ if getattr (resp , "background" , None ) is None :
734+ resp .background = background_tasks
735+ except Exception :
736+ pass
737+ return resp
733738
734739 origin_url = None if runtime .hide_origin_url_in_public_json else image .original_url
735740
@@ -856,16 +861,21 @@ def _needs_opportunistic_hydrate(image: Any) -> bool:
856861 range_header = request .headers .get ("Range" ),
857862 )
858863 if should_mark_ok :
859- _spawn_best_effort ( mark_image_ok ( engine , image_id = image_id , now = iso_utc_ms ()) )
864+ background_tasks . add_task ( _best_effort , mark_image_ok , engine , image_id = image_id , now = iso_utc_ms (), timeout_s = 1.5 )
860865 if needs_hydrate :
861- try :
862- await enqueue_opportunistic_hydrate_metadata (
863- engine ,
864- illust_id = illust_id_for_hydrate ,
865- reason = "random" ,
866- )
867- except Exception :
868- pass
866+ background_tasks .add_task (
867+ _best_effort ,
868+ enqueue_opportunistic_hydrate_metadata ,
869+ engine ,
870+ illust_id = illust_id_for_hydrate ,
871+ reason = "random" ,
872+ timeout_s = 2.5 ,
873+ )
874+ try :
875+ if getattr (resp , "background" , None ) is None :
876+ resp .background = background_tasks
877+ except Exception :
878+ pass
869879 return resp
870880 except ApiError as exc :
871881 if exc .code in {
@@ -874,14 +884,14 @@ def _needs_opportunistic_hydrate(image: Any) -> bool:
874884 ErrorCode .UPSTREAM_404 ,
875885 ErrorCode .UPSTREAM_RATE_LIMIT ,
876886 }:
877- _spawn_best_effort (
878- mark_image_failure (
879- engine ,
880- image_id = image_id ,
881- now = iso_utc_ms (),
882- error_code = exc .code .value ,
883- error_message = exc .message ,
884- )
887+ await _best_effort (
888+ mark_image_failure ,
889+ engine ,
890+ image_id = image_id ,
891+ now = iso_utc_ms (),
892+ error_code = exc .code .value ,
893+ error_message = exc .message ,
894+ timeout_s = 1.5 ,
885895 )
886896 tried_ids .add (image_id )
887897 last_error = exc
0 commit comments