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,9 +55,10 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
mapper = BankverbindungenMapper() mapper = BankverbindungenMapper()
notification_mgr = NotificationManager(espocrm_api=espocrm, context=ctx) notification_mgr = NotificationManager(espocrm_api=espocrm, context=ctx)
lock_key = f"sync_lock:cbankverbindungen:{entity_id}"
acquired = False
try: try:
# 1. ACQUIRE LOCK # 1. ACQUIRE LOCK
lock_key = f"sync_lock:cbankverbindungen:{entity_id}"
acquired = redis_client.set(lock_key, "locked", nx=True, ex=900) # 15min TTL acquired = redis_client.set(lock_key, "locked", nx=True, ex=900) # 15min TTL
if not acquired: if not acquired:
@@ -69,7 +70,6 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
espo_entity = await espocrm.get_entity('CBankverbindungen', entity_id) espo_entity = await espocrm.get_entity('CBankverbindungen', entity_id)
except Exception as e: except Exception as e:
ctx.logger.error(f"❌ Fehler beim Laden von EspoCRM Entity: {e}") ctx.logger.error(f"❌ Fehler beim Laden von EspoCRM Entity: {e}")
redis_client.delete(lock_key)
return return
ctx.logger.info(f"📋 Entity geladen: {espo_entity.get('name', 'Unbenannt')} (IBAN: {espo_entity.get('iban', 'N/A')})") ctx.logger.info(f"📋 Entity geladen: {espo_entity.get('name', 'Unbenannt')} (IBAN: {espo_entity.get('iban', 'N/A')})")
@@ -79,7 +79,6 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
if not beteiligte_id: if not beteiligte_id:
ctx.logger.error(f"❌ Keine cBeteiligteId gefunden - Bankverbindung muss einem Beteiligten zugeordnet sein") ctx.logger.error(f"❌ Keine cBeteiligteId gefunden - Bankverbindung muss einem Beteiligten zugeordnet sein")
redis_client.delete(lock_key)
return return
# Hole betNr vom Parent # Hole betNr vom Parent
@@ -88,7 +87,6 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
if not betnr: if not betnr:
ctx.logger.error(f"❌ Parent Beteiligter {beteiligte_id} hat keine betNr") ctx.logger.error(f"❌ Parent Beteiligter {beteiligte_id} hat keine betNr")
redis_client.delete(lock_key)
return return
# 3. BESTIMME SYNC-AKTION # 3. BESTIMME SYNC-AKTION
@@ -107,17 +105,19 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
else: else:
ctx.logger.warn(f"⚠️ Unbekannte Kombination: action={action}, advowareId={advoware_id}") ctx.logger.warn(f"⚠️ Unbekannte Kombination: action={action}, advowareId={advoware_id}")
redis_client.delete(lock_key)
except Exception as e: except Exception as e:
ctx.logger.error(f"❌ Unerwarteter Fehler im Sync-Handler: {e}") ctx.logger.error(f"❌ Unerwarteter Fehler im Sync-Handler: {e}")
import traceback import traceback
ctx.logger.error(traceback.format_exc()) ctx.logger.error(traceback.format_exc())
raise
finally:
if acquired:
try: try:
redis_client.delete(lock_key) redis_client.delete(lock_key)
except: except Exception as cleanup_err:
pass 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: async def handle_create(entity_id, betnr, espo_entity, espocrm, advoware, mapper, ctx, redis_client, lock_key) -> None: