Skip to content

Commit 80919a9

Browse files
committed
fix: better error handling
1 parent ada3fcf commit 80919a9

3 files changed

Lines changed: 46 additions & 47 deletions

File tree

app/activities/extract_pdf_content.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import httpx
2+
from fastapi import HTTPException
23
from pydantic import BaseModel
34
from temporalio import activity
45
from temporalio.exceptions import ApplicationError
56

6-
from app.config import Environment, get_settings
7+
from app.config import get_settings
78
from app.extractors import get_extractor
89

910
settings = get_settings()
@@ -28,7 +29,7 @@ class ExtractPdfContentResponse(BaseModel):
2829
@activity.defn
2930
async def create(request: ExtractPdfContentRequest) -> ExtractPdfContentResponse:
3031
"""Read a file and extract its text content using the specified extractor."""
31-
if settings.orcha_env in {Environment.LOCAL, Environment.DEV}:
32+
if settings.orcha_env in {"local", "dev"}:
3233
try:
3334
with open(request.url, "rb") as f:
3435
pdf_bytes = f.read()
@@ -39,9 +40,20 @@ async def create(request: ExtractPdfContentRequest) -> ExtractPdfContentResponse
3940
) from e
4041
else:
4142
async with httpx.AsyncClient() as client:
42-
response = await client.get(request.url)
43-
response.raise_for_status()
44-
pdf_bytes = response.content
43+
try:
44+
response = await client.get(request.url)
45+
response.raise_for_status()
46+
pdf_bytes = response.content
47+
except httpx.TimeoutException:
48+
raise HTTPException(
49+
status_code=504,
50+
detail="Request to fetch file timed out.",
51+
)
52+
except httpx.HTTPError as e:
53+
raise HTTPException(
54+
status_code=502,
55+
detail=f"Failed to fetch file from URL: {e.response.text}.",
56+
)
4557

4658
# Extract content using the extraction module
4759
try:

app/config.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
11
"""Centralized application settings using Pydantic Settings."""
22

3-
from enum import Enum
43
from functools import lru_cache
54

65
from pydantic_settings import BaseSettings
76

87

9-
class Environment(str, Enum):
10-
"""Application environment."""
11-
12-
LOCAL = "local"
13-
DEV = "dev"
14-
QA = "qa"
15-
PROD = "prod"
16-
17-
188
class Settings(BaseSettings):
199
"""Application configuration loaded from environment variables."""
2010

@@ -37,7 +27,7 @@ class Settings(BaseSettings):
3727
allowed_origins: list[str] = ["http://localhost:3000", "http://127.0.0.1:3000"]
3828

3929
# Environment
40-
orcha_env: Environment = Environment.LOCAL
30+
orcha_env: str = "local"
4131

4232
@property
4333
def database_url(self) -> str:

app/routers/workflows.py

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastapi import APIRouter, Depends, HTTPException, Request
77
from pydantic import BaseModel
88
from sqlalchemy.exc import SQLAlchemyError
9+
from sqlalchemy.orm.exc import NoResultFound
910
from sqlmodel import Session, select
1011
from sse_starlette import EventSourceResponse, ServerSentEvent
1112
from temporalio.client import Client
@@ -14,6 +15,7 @@
1415
from app.database.models import Workflow, WorkflowStatus
1516
from app.database.session import get_session
1617
from app.dependencies import get_current_user
18+
from app.errors import WorkflowEventError
1719
from app.workflows.extract_metadata_workflow import ExtractMetadata
1820

1921
router = APIRouter(
@@ -150,48 +152,43 @@ async def workflow_event(request: Request, workflow_id: str):
150152
if await request.is_disconnected():
151153
break
152154

153-
with Session(request.app.state.db_engine) as session:
154-
try:
155-
workflow = session.exec(
156-
select(Workflow).where(Workflow.public_id == workflow_id)
157-
).one()
158-
159-
status = workflow.status
160-
161-
if status == WorkflowStatus.SUCCESS:
162-
yield ServerSentEvent(
163-
data=json.dumps(workflow.result), event="metadata"
164-
)
165-
yield ServerSentEvent(data="done", event="end")
166-
break
167-
168-
if status == WorkflowStatus.ERROR:
169-
yield ServerSentEvent(
170-
# TODO: improve it with a better error message for end users
171-
data="The Temporal Workflow failed",
172-
event="error",
173-
)
174-
yield ServerSentEvent(data="done", event="end")
175-
break
176-
177-
except SQLAlchemyError as e:
178-
print("Error in fetching from database (stream_workflow)", e)
155+
try:
156+
with Session(request.app.state.db_engine) as session:
157+
try:
158+
workflow = session.exec(
159+
select(Workflow).where(Workflow.public_id == workflow_id)
160+
).one()
161+
except NoResultFound:
162+
raise WorkflowEventError(error_code="WORKFLOW_NOT_FOUND")
163+
except SQLAlchemyError as e:
164+
print("Error in fetching from database (stream_workflow)", e)
165+
raise WorkflowEventError(error_code="DB_FETCH_FAILED")
166+
167+
status = workflow.status
168+
169+
if status == WorkflowStatus.SUCCESS:
179170
yield ServerSentEvent(
180-
data="Failed to read workflow status.",
181-
event="error",
171+
data=json.dumps(workflow.result), event="metadata"
182172
)
183173
yield ServerSentEvent(data="done", event="end")
184174
break
185175

186-
except Exception as e:
187-
print("Error(stream_workflow)", e)
176+
if status == WorkflowStatus.ERROR:
188177
yield ServerSentEvent(
189-
data="An unexpected error occurred while streaming workflow results.", # noqa: E501
178+
data=json.dumps({"error_code": "WORKFLOW_FAILED"}),
190179
event="error",
191180
)
192181
yield ServerSentEvent(data="done", event="end")
193182
break
194183

184+
except WorkflowEventError as e:
185+
yield ServerSentEvent(
186+
data=json.dumps({"error_code": e.error_code}),
187+
event="error",
188+
)
189+
yield ServerSentEvent(data="done", event="end")
190+
break
191+
195192
await asyncio.sleep(STREAM_DELAY)
196193

197194

0 commit comments

Comments
 (0)