fix: [30388f42] Mache den Worker robust gegenüber gelöschten Entitäten
- Fügt eine zum hinzu, die bei einem HTTP 404 Fehler ausgelöst wird. - Fängt diese im ab. - Markiert Jobs, die sich auf nicht (mehr) existierende Kontakte oder Personen beziehen, als anstatt . - Dies verhindert, dass die Fehlerwarteschlange mit Jobs für gelöschte Entitäten überläuft, was das Hauptproblem der "failed"-Jobs löst.
This commit is contained in:
@@ -8,6 +8,10 @@ import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("superoffice-client")
|
||||
|
||||
class ContactNotFoundException(Exception):
|
||||
"""Custom exception for 404 errors on Contact/Person lookups."""
|
||||
pass
|
||||
|
||||
class SuperOfficeClient:
|
||||
"""A client for interacting with the SuperOffice REST API."""
|
||||
|
||||
@@ -117,6 +121,11 @@ class SuperOfficeClient:
|
||||
return resp.json()
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
# Explicitly handle 404 Not Found for GET requests
|
||||
if method == "GET" and e.response.status_code == 404:
|
||||
logger.warning(f"🔍 404 Not Found for GET request to {endpoint}.")
|
||||
raise ContactNotFoundException(f"Entity not found at {endpoint}") from e
|
||||
|
||||
logger.error(f"❌ API {method} Error for {endpoint} (Status: {e.response.status_code}): {e.response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
|
||||
@@ -5,7 +5,7 @@ import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
from queue_manager import JobQueue
|
||||
from superoffice_client import SuperOfficeClient
|
||||
from superoffice_client import SuperOfficeClient, ContactNotFoundException
|
||||
from config import settings
|
||||
|
||||
# Setup Logging
|
||||
@@ -39,7 +39,7 @@ def process_job(job, so_client: SuperOfficeClient, queue: JobQueue):
|
||||
Returns: (STATUS, MESSAGE)
|
||||
STATUS: 'SUCCESS', 'SKIPPED', 'RETRY', 'FAILED'
|
||||
"""
|
||||
logger.info(f"--- [WORKER v1.9.1] Processing Job {job['id']} ({job['event_type']}) ---")
|
||||
logger.info(f"--- [WORKER v1.9.2] Processing Job {job['id']} ({job['event_type']}) ---")
|
||||
payload = job['payload']
|
||||
event_low = job['event_type'].lower()
|
||||
|
||||
@@ -93,6 +93,10 @@ def process_job(job, so_client: SuperOfficeClient, queue: JobQueue):
|
||||
contact_id = contact_obj.get("ContactId")
|
||||
elif "ContactId" in person_details:
|
||||
contact_id = person_details.get("ContactId")
|
||||
except ContactNotFoundException:
|
||||
msg = f"Skipping job because Person ID {person_id} was not found in SuperOffice (likely deleted)."
|
||||
logger.warning(msg)
|
||||
return ("SKIPPED", msg)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to fetch person details for {person_id}: {e}")
|
||||
|
||||
@@ -121,10 +125,6 @@ def process_job(job, so_client: SuperOfficeClient, queue: JobQueue):
|
||||
select=["Name", "UrlAddress", "Urls", "UserDefinedFields", "Address", "OrgNr", "Associate"]
|
||||
)
|
||||
|
||||
# ABSOLUTE SAFETY CHECK
|
||||
if contact_details is None:
|
||||
raise ValueError(f"SuperOffice API returned None for Contact {contact_id}. Possible timeout or record locked.")
|
||||
|
||||
crm_name = contact_details.get("Name", "Unknown")
|
||||
|
||||
# Safely get Associate object
|
||||
@@ -181,6 +181,9 @@ def process_job(job, so_client: SuperOfficeClient, queue: JobQueue):
|
||||
logger.info(f"🎯 CAMPAIGN DETECTED: '{campaign_tag}'")
|
||||
else:
|
||||
logger.info("ℹ️ No Campaign Tag found (Field is empty).")
|
||||
except ContactNotFoundException:
|
||||
# This is not critical, we can proceed without a campaign tag
|
||||
logger.warning(f"Could not fetch campaign tag: Person {person_id} not found.")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not fetch campaign tag: {e}")
|
||||
|
||||
@@ -197,7 +200,11 @@ def process_job(job, so_client: SuperOfficeClient, queue: JobQueue):
|
||||
crm_industry_name = vertical_map_rev[val_str]
|
||||
except Exception as ex:
|
||||
logger.error(f"Error mapping vertical ID {val_str}: {ex}")
|
||||
|
||||
|
||||
except ContactNotFoundException:
|
||||
msg = f"Skipping job because Contact ID {contact_id} was not found in SuperOffice (likely deleted)."
|
||||
logger.warning(msg)
|
||||
return ("SKIPPED", msg)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch contact details for {contact_id}: {e}")
|
||||
raise Exception(f"SuperOffice API Failure: {e}")
|
||||
@@ -231,7 +238,10 @@ def process_job(job, so_client: SuperOfficeClient, queue: JobQueue):
|
||||
|
||||
# Fetch fresh Contact Data for comparison
|
||||
contact_data = so_client.get_contact(contact_id)
|
||||
if not contact_data: return ("FAILED", "Could not fetch contact for patch")
|
||||
if not contact_data:
|
||||
# This can happen if the contact was deleted between the CE call and now
|
||||
logger.warning(f"Could not re-fetch contact {contact_id} for patch (deleted?). Skipping patch.")
|
||||
return ("SKIPPED", "Contact deleted post-analysis")
|
||||
|
||||
# SAFE GET FOR COMPARISON
|
||||
current_udfs = safe_get_udfs(contact_data)
|
||||
|
||||
Reference in New Issue
Block a user