Skip to content

Commit

Permalink
chore: add timeout for api
Browse files Browse the repository at this point in the history
  • Loading branch information
nquang29 committed Jan 5, 2025
1 parent 4e65dab commit cc0d751
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 9 deletions.
11 changes: 8 additions & 3 deletions app/lib/backend/http/api/conversations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ Future<CreateConversationResponse?> processInProgressConversation() async {
}

Future<List<ServerConversation>> getConversations(
{int limit = 50, int offset = 0, List<ConversationStatus> statuses = const []}) async {
{int limit = 50, int offset = 0, List<ConversationStatus> statuses = const [], int? segment_limit}) async {

var url = '${Env.apiBaseUrl}v1/memories?limit=$limit&offset=$offset&statuses=${statuses.map((val) => val.toString().split(".").last).join(",")}';
if (segment_limit != null) {
url += '&segment_limit=$segment_limit';
}

var response = await makeApiCall(
url:
'${Env.apiBaseUrl}v1/memories?limit=$limit&offset=$offset&statuses=${statuses.map((val) => val.toString().split(".").last).join(",")}',
url: url,
headers: {},
method: 'GET',
body: '');
Expand Down
2 changes: 1 addition & 1 deletion app/lib/providers/capture_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ class CaptureProvider extends ChangeNotifier
}

void _loadInProgressConversation() async {
var memories = await getConversations(statuses: [ConversationStatus.in_progress], limit: 1);
var memories = await getConversations(statuses: [ConversationStatus.in_progress], limit: 1, segment_limit: 50);
_inProgressConversation = memories.isNotEmpty ? memories.first : null;
if (_inProgressConversation != null) {
segments = _inProgressConversation!.transcriptSegments;
Expand Down
4 changes: 2 additions & 2 deletions app/lib/providers/conversation_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class ConversationProvider extends ChangeNotifier implements IWalServiceListener

Future getConversationsFromServer() async {
setLoadingConversations(true);
var mem = await getConversations();
var mem = await getConversations(segment_limit: 50);
conversations = mem;
conversations.sort((a, b) => b.createdAt.compareTo(a.createdAt));
setLoadingConversations(false);
Expand Down Expand Up @@ -181,7 +181,7 @@ class ConversationProvider extends ChangeNotifier implements IWalServiceListener
if (conversations.length % 50 != 0) return;
if (isLoadingConversations) return;
setLoadingConversations(true);
var newConversations = await getConversations(offset: conversations.length);
var newConversations = await getConversations(offset: conversations.length, segment_limit: 50);
conversations.addAll(newConversations);
conversations.sort((a, b) => b.createdAt.compareTo(a.createdAt));
filterGroupedConversations(previousQuery);
Expand Down
11 changes: 11 additions & 0 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from modal import Image, App, asgi_app, Secret
from routers import workflow, chat, firmware, plugins, memories, transcribe_v2, notifications, \
speech_profile, agents, facts, users, processing_memories, trends, sdcard, sync, apps, custom_auth, payment
from utils.other.timeout import TimeoutMiddleware

if os.environ.get('SERVICE_ACCOUNT_JSON'):
service_account_info = json.loads(os.environ["SERVICE_ACCOUNT_JSON"])
Expand Down Expand Up @@ -40,6 +41,16 @@

app.include_router(payment.router)


methods_timeout = {
"GET": os.environ.get('HTTP_GET_TIMEOUT'),
"PUT": os.environ.get('HTTP_PUT_TIMEOUT'),
"PATCH": os.environ.get('HTTP_PATCH_TIMEOUT'),
"DELETE": os.environ.get('HTTP_DELETE_TIMEOUT'),
}

app.add_middleware(TimeoutMiddleware,methods_timeout=methods_timeout)

modal_app = App(
name='backend',
secrets=[Secret.from_name("gcp-credentials"), Secret.from_name('envs')],
Expand Down
9 changes: 6 additions & 3 deletions backend/routers/memories.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,14 @@ def reprocess_memory(


@router.get('/v1/memories', response_model=List[Memory], tags=['memories'])
def get_memories(limit: int = 100, offset: int = 0, statuses: str = "", uid: str = Depends(auth.get_current_user_uid)):
def get_memories(limit: int = 100, offset: int = 0, statuses: str = "", segment_limit: int = None, uid: str = Depends(auth.get_current_user_uid)):
print('get_memories', uid, limit, offset, statuses)
return memories_db.get_memories(uid, limit, offset, include_discarded=True,
memories = memories_db.get_memories(uid, limit, offset, include_discarded=True,
statuses=statuses.split(",") if len(statuses) > 0 else [])

if segment_limit is not None:
for memory in memories:
memory["transcript_segments"] = memory.get("transcript_segments", [])[:segment_limit]
return memories

@router.get("/v1/memories/{memory_id}", response_model=Memory, tags=['memories'])
def get_memory_by_id(memory_id: str, uid: str = Depends(auth.get_current_user_uid)):
Expand Down
40 changes: 40 additions & 0 deletions backend/utils/other/timeout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
from fastapi import Request
import asyncio
import os

class TimeoutMiddleware(BaseHTTPMiddleware):
def __init__(self, app, methods_timeout: dict = None):
super().__init__(app)

self.default_timeout = self._get_timeout_from_env("HTTP_DEFAULT_TIMEOUT", default=2 * 60)

self.methods_timeout = self._parse_methods_timeout(methods_timeout or {})

@staticmethod
def _get_timeout_from_env(env_var: str, default: float) -> float:
timeout = os.environ.get(env_var, default)
try:
return float(timeout)
except ValueError:
raise ValueError(f"Invalid timeout value in env {env_var}: {timeout}")

@staticmethod
def _parse_methods_timeout(methods_timeout: dict) -> dict:
result = {}
for method, timeout in methods_timeout.items():
if timeout is None:
continue
try:
result[method.upper()] = float(timeout)
except ValueError:
raise ValueError(f"Invalid timeout value for method {method}: {timeout}")
return result

async def dispatch(self, request: Request, call_next):
timeout = self.methods_timeout.get(request.method, self.default_timeout)
try:
return await asyncio.wait_for(call_next(request), timeout=timeout)
except asyncio.TimeoutError:
return Response(status_code=504)

0 comments on commit cc0d751

Please sign in to comment.