Fix SSL/TLS handshake failure - simplify httpx client creation
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Removed manual SSL context creation that was causing handshake failures - Simplified create_http_client() to let httpx handle SSL negotiation directly - Disabled HTTP/2 for better compatibility - Added proper connection limits and timeouts - Updated all three client instantiations to await the async function - Improved overall SSL/TLS stability for Meta API connections
This commit is contained in:
parent
18de92aa3a
commit
9b6f053d86
94
backend/test_whatsapp_send.py
Normal file
94
backend/test_whatsapp_send.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to send WhatsApp message via template
|
||||||
|
Usage: python test_whatsapp_send.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Import after logging is configured
|
||||||
|
from database import SessionLocal
|
||||||
|
from whatsapp import WhatsAppService
|
||||||
|
|
||||||
|
|
||||||
|
async def test_send_whatsapp():
|
||||||
|
"""Test sending a WhatsApp message using hina_invitation template"""
|
||||||
|
|
||||||
|
db = SessionLocal()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Initialize WhatsApp service
|
||||||
|
service = WhatsAppService(db=db)
|
||||||
|
|
||||||
|
# Phone number to test (Israeli format)
|
||||||
|
phone = "0504370045"
|
||||||
|
|
||||||
|
# Template parameters for hina_invitation
|
||||||
|
params = {
|
||||||
|
"contact_name": "דוד",
|
||||||
|
"event_date": "17/05",
|
||||||
|
"event_date_day": "17",
|
||||||
|
"venue": "אולם הגן",
|
||||||
|
"location": "ירושלים",
|
||||||
|
"reception_time": "18:30",
|
||||||
|
"ceremony_time": "19:00",
|
||||||
|
"dinner_time": "20:00",
|
||||||
|
"bride_name": "ורד",
|
||||||
|
"groom_name": "דביר",
|
||||||
|
"event_id": "f3122a7d-1d7c-4cc1-955d-1c6b7358bd25"
|
||||||
|
}
|
||||||
|
|
||||||
|
print("\n" + "="*80)
|
||||||
|
print("TESTING WHATSAPP MESSAGE SEND")
|
||||||
|
print("="*80)
|
||||||
|
print(f"Phone: {phone}")
|
||||||
|
print(f"Template: hina_invitation")
|
||||||
|
print(f"Parameters: {params}")
|
||||||
|
print("="*80 + "\n")
|
||||||
|
|
||||||
|
# Send the message
|
||||||
|
logger.info(f"Attempting to send WhatsApp message to {phone}")
|
||||||
|
result = await service.send_by_template_key(
|
||||||
|
template_key="wedding_invitation_by_vered",
|
||||||
|
to_phone=phone,
|
||||||
|
params=params
|
||||||
|
)
|
||||||
|
|
||||||
|
print("\n" + "="*80)
|
||||||
|
print("SUCCESS!")
|
||||||
|
print("="*80)
|
||||||
|
print(f"Result: {result}")
|
||||||
|
print("="*80 + "\n")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("\n" + "="*80)
|
||||||
|
print("ERROR!")
|
||||||
|
print("="*80)
|
||||||
|
print(f"Error: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
print("="*80 + "\n")
|
||||||
|
raise
|
||||||
|
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_send_whatsapp())
|
||||||
@ -3,7 +3,6 @@ WhatsApp Cloud API Service
|
|||||||
Handles sending WhatsApp messages via Meta's API
|
Handles sending WhatsApp messages via Meta's API
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import ssl
|
|
||||||
import httpx
|
import httpx
|
||||||
import certifi
|
import certifi
|
||||||
import re
|
import re
|
||||||
@ -15,32 +14,19 @@ from datetime import datetime
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def create_http_client() -> httpx.AsyncClient:
|
async def create_http_client() -> httpx.AsyncClient:
|
||||||
"""
|
"""
|
||||||
Create an httpx client with robust SSL configuration.
|
Create an httpx client with proper certificate verification.
|
||||||
Tries to use system certificates first, falls back to certifi.
|
Uses certifi for CA bundle and lets httpx handle SSL/TLS negotiation.
|
||||||
"""
|
"""
|
||||||
try:
|
# Let httpx use certifi's CA bundle - simpler and more reliable
|
||||||
# Try using system SSL context with certifi certificates
|
return httpx.AsyncClient(
|
||||||
ssl_context = ssl.create_default_context(cafile=certifi.where())
|
verify=certifi.where(),
|
||||||
# Enable hostname checking but allow some TLS flexibility
|
timeout=httpx.Timeout(30.0, connect=10.0),
|
||||||
ssl_context.check_hostname = True
|
http2=False, # Disable HTTP/2 to avoid compatibility issues
|
||||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
limits=httpx.Limits(max_keepalive_connections=5, max_connections=10)
|
||||||
# Use more compatible TLS versions
|
)
|
||||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
||||||
|
|
||||||
return httpx.AsyncClient(verify=ssl_context, timeout=30.0)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"[WhatsApp] Failed to create SSL context with certifi: {e}. Trying default SSL.")
|
|
||||||
try:
|
|
||||||
# Fallback to default SSL context
|
|
||||||
ssl_context = ssl.create_default_context()
|
|
||||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
||||||
return httpx.AsyncClient(verify=ssl_context, timeout=30.0)
|
|
||||||
except Exception as e2:
|
|
||||||
logger.error(f"[WhatsApp] Failed to create SSL context: {e2}. Using basic client.")
|
|
||||||
# Last resort fallback - httpx will use its own SSL handling
|
|
||||||
return httpx.AsyncClient(timeout=30.0)
|
|
||||||
|
|
||||||
|
|
||||||
class WhatsAppError(Exception):
|
class WhatsAppError(Exception):
|
||||||
@ -195,7 +181,7 @@ class WhatsAppService:
|
|||||||
url = f"{self.base_url}/{self.phone_number_id}/messages"
|
url = f"{self.base_url}/{self.phone_number_id}/messages"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with create_http_client() as client:
|
async with await create_http_client() as client:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
url,
|
url,
|
||||||
json=payload,
|
json=payload,
|
||||||
@ -325,7 +311,7 @@ class WhatsAppService:
|
|||||||
print("=" * 80 + "\n")
|
print("=" * 80 + "\n")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with create_http_client() as client:
|
async with await create_http_client() as client:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
url,
|
url,
|
||||||
json=payload,
|
json=payload,
|
||||||
@ -588,7 +574,7 @@ class WhatsAppService:
|
|||||||
|
|
||||||
url = f"{self.base_url}/{self.phone_number_id}/messages"
|
url = f"{self.base_url}/{self.phone_number_id}/messages"
|
||||||
try:
|
try:
|
||||||
async with create_http_client() as client:
|
async with await create_http_client() as client:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
url,
|
url,
|
||||||
json=payload,
|
json=payload,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user