diff --git a/src/steps/crm/bankverbindungen/bankverbindungen_sync_event_step.py b/src/steps/crm/bankverbindungen/bankverbindungen_sync_event_step.py index a13b145..cfd297f 100644 --- a/src/steps/crm/bankverbindungen/bankverbindungen_sync_event_step.py +++ b/src/steps/crm/bankverbindungen/bankverbindungen_sync_event_step.py @@ -55,69 +55,69 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None: mapper = BankverbindungenMapper() notification_mgr = NotificationManager(espocrm_api=espocrm, context=ctx) + lock_key = f"sync_lock:cbankverbindungen:{entity_id}" + acquired = False try: # 1. ACQUIRE LOCK - lock_key = f"sync_lock:cbankverbindungen:{entity_id}" acquired = redis_client.set(lock_key, "locked", nx=True, ex=900) # 15min TTL - + if not acquired: ctx.logger.warn(f"⏸️ Sync bereits aktiv für {entity_id}, überspringe") return - + # 2. FETCH ENTITY VON ESPOCRM try: espo_entity = await espocrm.get_entity('CBankverbindungen', entity_id) except Exception as e: ctx.logger.error(f"❌ Fehler beim Laden von EspoCRM Entity: {e}") - redis_client.delete(lock_key) return - + ctx.logger.info(f"📋 Entity geladen: {espo_entity.get('name', 'Unbenannt')} (IBAN: {espo_entity.get('iban', 'N/A')})") - + advoware_id = espo_entity.get('advowareId') beteiligte_id = espo_entity.get('cBeteiligteId') # Parent Beteiligter - + if not beteiligte_id: ctx.logger.error(f"❌ Keine cBeteiligteId gefunden - Bankverbindung muss einem Beteiligten zugeordnet sein") - redis_client.delete(lock_key) return - + # Hole betNr vom Parent parent = await espocrm.get_entity('CBeteiligte', beteiligte_id) betnr = parent.get('betnr') - + if not betnr: ctx.logger.error(f"❌ Parent Beteiligter {beteiligte_id} hat keine betNr") - redis_client.delete(lock_key) return - + # 3. BESTIMME SYNC-AKTION - + # FALL A: Neu (kein advowareId) → CREATE in Advoware if not advoware_id and action in ['create', 'sync_check']: await handle_create(entity_id, betnr, espo_entity, espocrm, advoware, mapper, ctx, redis_client, lock_key) - + # FALL B: Existiert (hat advowareId) → UPDATE oder CHECK (nicht unterstützt!) elif advoware_id and action in ['update', 'sync_check']: await handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, notification_mgr, ctx, redis_client, lock_key) - + # FALL C: DELETE (nicht unterstützt!) elif action == 'delete': await handle_delete(entity_id, betnr, advoware_id, espo_entity, espocrm, notification_mgr, ctx, redis_client, lock_key) - + else: ctx.logger.warn(f"⚠️ Unbekannte Kombination: action={action}, advowareId={advoware_id}") - redis_client.delete(lock_key) - + except Exception as e: ctx.logger.error(f"❌ Unerwarteter Fehler im Sync-Handler: {e}") import traceback ctx.logger.error(traceback.format_exc()) - - try: - redis_client.delete(lock_key) - except: - pass + raise + + finally: + if acquired: + try: + redis_client.delete(lock_key) + except Exception as cleanup_err: + ctx.logger.error(f"❌ Lock-Release fehlgeschlagen: {cleanup_err}") async def handle_create(entity_id, betnr, espo_entity, espocrm, advoware, mapper, ctx, redis_client, lock_key) -> None: