diff --git a/src/messaging/flow/flow-execution.service.ts b/src/messaging/flow/flow-execution.service.ts index 770aad5..b31c797 100644 --- a/src/messaging/flow/flow-execution.service.ts +++ b/src/messaging/flow/flow-execution.service.ts @@ -44,9 +44,28 @@ export class FlowExecutionService { this.auth = apiKey ? `Bearer ${apiKey}` : ''; } + // Per-phone lock to prevent concurrent flow executions + private readonly locks = new Map>(); + async handleMessage(message: NormalizedMessage): Promise { const { phone } = message; + // Serialize executions per phone — prevent two concurrent flows + const existing = this.locks.get(phone); + const execute = async () => { + if (existing) await existing.catch(() => {}); + await this._handleMessage(message); + }; + const promise = execute(); + this.locks.set(phone, promise); + await promise.finally(() => { + if (this.locks.get(phone) === promise) this.locks.delete(phone); + }); + } + + private async _handleMessage(message: NormalizedMessage): Promise { + const { phone } = message; + // 1. Load existing session or start new flow let session = await this.sessions.load(phone); let flow: Flow | null = null;