Add exponential backoff for Google API calls

- Use backoff library with 5s base, max 5 tries for HttpError 429/5xx
- Decorate Google functions: ensure_calendar, fetch_events, create/update/delete events
- Add backoff to requirements.txt
This commit is contained in:
root
2025-10-23 12:49:45 +00:00
parent 0d758b07ea
commit 48ce8d8e73
2 changed files with 8 additions and 1 deletions

View File

@@ -6,3 +6,4 @@ redis
python-dotenv python-dotenv
google-api-python-client google-api-python-client
google-auth google-auth
backoff

View File

@@ -4,6 +4,7 @@ import os
import datetime import datetime
from datetime import timedelta from datetime import timedelta
import pytz import pytz
import backoff
from googleapiclient.discovery import build from googleapiclient.discovery import build
from googleapiclient.errors import HttpError from googleapiclient.errors import HttpError
from google.oauth2 import service_account from google.oauth2 import service_account
@@ -60,6 +61,7 @@ async def get_google_service():
logger.error(f"Failed to initialize Google service: {e}") logger.error(f"Failed to initialize Google service: {e}")
raise raise
@backoff.on_exception(backoff.expo, HttpError, max_tries=5, base=5, giveup=lambda e: e.resp.status not in [429, 500, 502, 503, 504])
async def ensure_google_calendar(service, employee_kuerzel): async def ensure_google_calendar(service, employee_kuerzel):
"""Ensure Google Calendar exists for employee.""" """Ensure Google Calendar exists for employee."""
calendar_name = f"AW-{employee_kuerzel}" calendar_name = f"AW-{employee_kuerzel}"
@@ -106,6 +108,7 @@ async def fetch_advoware_appointments(advoware, employee_kuerzel):
logger.error(f"Failed to fetch Advoware appointments: {e}") logger.error(f"Failed to fetch Advoware appointments: {e}")
raise raise
@backoff.on_exception(backoff.expo, HttpError, max_tries=5, base=5, giveup=lambda e: e.resp.status not in [429, 500, 502, 503, 504])
async def fetch_google_events(service, calendar_id): async def fetch_google_events(service, calendar_id):
"""Fetch Google events in range.""" """Fetch Google events in range."""
try: try:
@@ -287,6 +290,7 @@ async def delete_advoware_appointment(advoware, frnr):
logger.error(f"Failed to delete Advoware appointment {frnr}: {e}") logger.error(f"Failed to delete Advoware appointment {frnr}: {e}")
raise raise
@backoff.on_exception(backoff.expo, HttpError, max_tries=5, base=5, giveup=lambda e: e.resp.status not in [429, 500, 502, 503, 504])
async def create_google_event(service, calendar_id, data): async def create_google_event(service, calendar_id, data):
"""Create Google event from standardized data.""" """Create Google event from standardized data."""
start_dt = data['start'].astimezone(BERLIN_TZ) start_dt = data['start'].astimezone(BERLIN_TZ)
@@ -320,6 +324,7 @@ async def create_google_event(service, calendar_id, data):
logger.error(f"Failed to create Google event: {e}") logger.error(f"Failed to create Google event: {e}")
raise raise
@backoff.on_exception(backoff.expo, HttpError, max_tries=5, base=5, giveup=lambda e: e.resp.status not in [429, 500, 502, 503, 504])
async def update_google_event(service, calendar_id, event_id, data): async def update_google_event(service, calendar_id, event_id, data):
"""Update Google event.""" """Update Google event."""
start_dt = data['start'].astimezone(BERLIN_TZ) start_dt = data['start'].astimezone(BERLIN_TZ)
@@ -351,6 +356,7 @@ async def update_google_event(service, calendar_id, event_id, data):
logger.error(f"Failed to update Google event {event_id}: {e}") logger.error(f"Failed to update Google event {event_id}: {e}")
raise raise
@backoff.on_exception(backoff.expo, HttpError, max_tries=5, base=5, giveup=lambda e: e.resp.status not in [429, 500, 502, 503, 504])
async def delete_google_event(service, calendar_id, event_id): async def delete_google_event(service, calendar_id, event_id):
"""Delete Google event.""" """Delete Google event."""
try: try: