fix: add try/finally for lock release in bankverbindungen_sync handler – prevents 15-min lock leaks on exception

This commit is contained in:
bsiggel
2026-03-31 06:59:03 +00:00
parent 7a0ebb949d
commit 814e869ca0

View File

@@ -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: