1818def lambda_handler (event : dict , context : Any ) -> dict :
1919 """SQS Consumer Lambda entry point."""
2020 for record in event ['Records' ]:
21- message_data = json .loads (record ['body' ])
22- asyncio .run (process_message (message_data ))
21+ try :
22+ message_data = json .loads (record ['body' ])
23+ except json .JSONDecodeError as e :
24+ # Invalid message format - log and skip
25+ import logging
26+ logger = logging .getLogger ()
27+ logger .error (f"Failed to parse SQS message: { e } " )
28+ continue
29+
30+ try :
31+ asyncio .run (process_message (message_data ))
32+ except Exception as e :
33+ # Log and let SQS retry on failure
34+ import logging
35+ logger = logging .getLogger ()
36+ logger .exception (f"Failed to process message: { e } " )
37+ raise # Re-raise to fail the batch item
2338
2439 return {'statusCode' : 200 }
2540
2641
2742async def process_message (message_data : dict ) -> None :
2843 """Process single message from SQS queue."""
44+ import logging
45+ logger = logging .getLogger ()
46+
2947 config = Config .from_env ()
3048 bot = Bot (config .telegram_token )
3149
3250 # Reconstruct Update object from stored data
3351 update = Update .de_json (message_data ['telegram_update' ], bot )
3452 message = update .message or update .edited_message
3553
54+ if not message :
55+ logger .warning ("Received update with no message or edited_message" )
56+ return
57+
3658 # Send typing indicator
3759 await bot .send_chat_action (
3860 chat_id = message .chat_id ,
3961 action = ChatAction .TYPING ,
4062 message_thread_id = message .message_thread_id ,
4163 )
4264
65+ # Initialize result with default error response
66+ # This ensures result is always defined, even if Agent Server call fails
67+ result = {
68+ 'response' : '' ,
69+ 'is_error' : True ,
70+ 'error_message' : 'Failed to get response from Agent Server'
71+ }
72+
4373 # Call Agent Server
4474 try :
4575 async with httpx .AsyncClient (timeout = 600.0 ) as client :
@@ -59,6 +89,7 @@ async def process_message(message_data: dict) -> None:
5989 result = response .json ()
6090
6191 except httpx .TimeoutException :
92+ logger .warning (f"Agent Server timeout for chat_id={ message .chat_id } " )
6293 await bot .send_message (
6394 chat_id = message .chat_id ,
6495 text = "Request timed out." ,
@@ -67,19 +98,23 @@ async def process_message(message_data: dict) -> None:
6798 raise # Re-raise to trigger SQS retry for transient errors
6899
69100 except Exception as e :
70- await bot .send_message (
71- chat_id = message .chat_id ,
72- text = f"Error: { str (e )[:200 ]} " ,
73- message_thread_id = message .message_thread_id ,
74- )
75- # Don't re-raise for general exceptions - error message already sent
76- # to user, retrying would cause duplicate messages
101+ logger .exception (f"Agent Server error for chat_id={ message .chat_id } " )
102+ error_text = f"Error: { str (e )[:200 ]} "
103+ try :
104+ await bot .send_message (
105+ chat_id = message .chat_id ,
106+ text = error_text ,
107+ message_thread_id = message .message_thread_id ,
108+ )
109+ except Exception as send_error :
110+ logger .error (f"Failed to send error message to Telegram: { send_error } " )
111+ # Don't re-raise - error message already sent to user, retrying would cause duplicate messages
77112
78- # Format response
113+ # Format response (result is guaranteed to be defined now)
79114 if result .get ('is_error' ):
80115 text = f"Agent error: { result .get ('error_message' , 'Unknown' )} "
81116 else :
82- text = result .get ('response' , 'No response' )
117+ text = result .get ('response' ) or 'No response'
83118
84119 if len (text ) > 4000 :
85120 text = text [:4000 ] + "\n \n ... (truncated)"
0 commit comments