Skip to content

Commit a080019

Browse files
committed
fix: race condition no pareamento - JID síncrono e sessionReady
1 parent e08c4aa commit a080019

File tree

2 files changed

+64
-15
lines changed

2 files changed

+64
-15
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## [v1.0.7] - 2026-01-19
4+
### Corrigido
5+
- **Race condition no pareamento**: salvamento do JID agora é síncrono, garantindo que a sessão esteja persistida antes de liberar para uso.
6+
- Mensagens ficando em "Aguardando" após conectar instância: adicionado controle `sessionReady` que indica quando a sessão está pronta para enviar mensagens (após presence enviado).
7+
8+
### Adicionado
9+
- Método `IsSessionReady()` no Manager para verificar se a sessão está completamente pronta para operações de envio.
10+
11+
### Internals
12+
- Limpeza automática do estado `sessionReady` e `pairingSuccess` ao deletar sessão.
13+
314
## [v1.0.6] - 2026-01-18
415
### Adicionado
516
- Implementação de **Smart Debounce** para estabilização de conexão: desconexões acidentais são filtradas por 5 segundos antes de disparar webhook, enquanto desconexões intencionais (API/Logout) são notificadas imediatamente.

internal/session/whatsmeow/manager.go

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type Manager struct {
4545
currentQRs map[string]string
4646
qrContexts map[string]context.CancelFunc
4747
pairingSuccess map[string]time.Time
48+
sessionReady map[string]bool
4849
mu sync.RWMutex
4950
log *zap.Logger
5051
encKey string
@@ -77,6 +78,7 @@ func NewManager(log *zap.Logger, encKey, storageDriver, baseDir, pgConnString st
7778
currentQRs: make(map[string]string),
7879
qrContexts: make(map[string]context.CancelFunc),
7980
pairingSuccess: make(map[string]time.Time),
81+
sessionReady: make(map[string]bool),
8082
log: log,
8183
encKey: encKey,
8284
storageDriver: storageDriver,
@@ -127,6 +129,13 @@ func (m *Manager) GetSessionStorageInfo(instanceID string) SessionStorageInfo {
127129
}
128130
}
129131

132+
133+
func (m *Manager) IsSessionReady(instanceID string) bool {
134+
m.mu.RLock()
135+
defer m.mu.RUnlock()
136+
return m.sessionReady[instanceID]
137+
}
138+
130139
func (m *Manager) CreateSession(ctx context.Context, instanceID string) (string, error) {
131140
return m.createSession(ctx, instanceID, false)
132141
}
@@ -331,23 +340,21 @@ func (m *Manager) monitorQRChannel(instanceID string, client *whatsmeow.Client,
331340
m.pairingSuccess[instanceID] = time.Now()
332341
m.mu.Unlock()
333342

343+
334344
if client != nil && client.Store != nil && client.Store.ID != nil {
335-
go func() {
336-
if m.instanceRepo != nil {
337-
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
338-
defer cancel()
339-
340-
inst, err := m.instanceRepo.GetByID(ctx, instanceID)
341-
if err != nil {
342-
m.log.Error("erro ao buscar instância para salvar JID",
343-
zap.String("instance_id", instanceID),
344-
zap.Error(err),
345-
)
346-
return
347-
}
348-
345+
if m.instanceRepo != nil {
346+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
347+
inst, err := m.instanceRepo.GetByID(ctx, instanceID)
348+
if err != nil {
349+
m.log.Error("erro ao buscar instância para salvar JID",
350+
zap.String("instance_id", instanceID),
351+
zap.Error(err),
352+
)
353+
cancel()
354+
} else {
349355
inst.WhatsAppJID = client.Store.ID.String()
350356
_, err = m.instanceRepo.Update(ctx, inst)
357+
cancel()
351358
if err != nil {
352359
m.log.Error("erro ao salvar JID da instância",
353360
zap.String("instance_id", instanceID),
@@ -361,7 +368,7 @@ func (m *Manager) monitorQRChannel(instanceID string, client *whatsmeow.Client,
361368
)
362369
}
363370
}
364-
}()
371+
}
365372
}
366373

367374
go m.initHistorySyncCycle(instanceID)
@@ -381,9 +388,19 @@ func (m *Manager) monitorQRChannel(instanceID string, client *whatsmeow.Client,
381388
}
382389
} else {
383390
m.log.Info("presence enviado com sucesso", zap.String("instance_id", instanceID))
391+
392+
m.mu.Lock()
393+
m.sessionReady[instanceID] = true
394+
m.mu.Unlock()
395+
m.log.Info("sessão marcada como pronta para mensagens", zap.String("instance_id", instanceID))
384396
return
385397
}
386398
}
399+
400+
m.mu.Lock()
401+
m.sessionReady[instanceID] = true
402+
m.mu.Unlock()
403+
m.log.Warn("sessão marcada como pronta após falha no presence", zap.String("instance_id", instanceID))
387404
}()
388405

389406
go func() {
@@ -573,6 +590,8 @@ func (m *Manager) DeleteSession(instanceID string) error {
573590
delete(m.clients, instanceID)
574591
}
575592
delete(m.currentQRs, instanceID)
593+
delete(m.sessionReady, instanceID)
594+
delete(m.pairingSuccess, instanceID)
576595
m.mu.Unlock()
577596

578597
// Se o cliente não estiver em memória, tentar restaurar para realizar o logout
@@ -583,6 +602,7 @@ func (m *Manager) DeleteSession(instanceID string) error {
583602
// Remove do map novamente pois restoreSessionIfExists adiciona
584603
m.mu.Lock()
585604
delete(m.clients, instanceID)
605+
delete(m.sessionReady, instanceID)
586606
m.mu.Unlock()
587607
}
588608
}
@@ -952,9 +972,19 @@ func (m *Manager) restoreSessionIfExists(ctx context.Context, instanceID string)
952972
}
953973
} else {
954974
m.log.Info("presence enviado com sucesso", zap.String("instance_id", instanceID))
975+
976+
m.mu.Lock()
977+
m.sessionReady[instanceID] = true
978+
m.mu.Unlock()
979+
m.log.Info("sessão restaurada e pronta para mensagens", zap.String("instance_id", instanceID))
955980
return
956981
}
957982
}
983+
984+
m.mu.Lock()
985+
m.sessionReady[instanceID] = true
986+
m.mu.Unlock()
987+
m.log.Warn("sessão restaurada marcada como pronta após falha no presence", zap.String("instance_id", instanceID))
958988
}()
959989

960990
m.log.Info("sessão restaurada com sucesso", zap.String("instance_id", instanceID), zap.Bool("is_logged_in", client.IsLoggedIn()))
@@ -1291,9 +1321,17 @@ func (m *Manager) handleEvent(instanceID string, evt any) {
12911321
}
12921322
} else {
12931323
m.log.Info("presence enviado - instância totalmente ativa", zap.String("instance_id", instanceID))
1324+
1325+
m.mu.Lock()
1326+
m.sessionReady[instanceID] = true
1327+
m.mu.Unlock()
12941328
return
12951329
}
12961330
}
1331+
1332+
m.mu.Lock()
1333+
m.sessionReady[instanceID] = true
1334+
m.mu.Unlock()
12971335
}()
12981336
}
12991337

0 commit comments

Comments
 (0)