Skip to content

fix: logout instance#2501

Open
daniloleonecarneiro wants to merge 1 commit intodevelopfrom
fix/logout-baileys
Open

fix: logout instance#2501
daniloleonecarneiro wants to merge 1 commit intodevelopfrom
fix/logout-baileys

Conversation

@daniloleonecarneiro
Copy link
Copy Markdown

@daniloleonecarneiro daniloleonecarneiro commented Apr 8, 2026

📋 Description

Improves the reliability of the WhatsApp instance logout flow and prevents crashes during connection lifecycle events.

Changes in BaileysStartupService:

  • logoutInstance(): sets endSession = true before teardown so reconnection is suppressed; wraps client.logout() and client.ws.close() in individual try/catch blocks to gracefully handle already-disconnected states; forces stateConnection to { state: 'close', statusReason: 401 } and updates the instance connectionStatus to 'close' in the database after cleanup.
  • Adds status code 408 to codesToNotReconnect to avoid reconnection loops on request-timeout disconnects.
  • Adds a null guard for client.user?.id on connection === 'open' to prevent a TypeError crash when Baileys fires the open event before the user object is populated.

🔗 Related Issue

Closes #(issue_number)

🧪 Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧹 Code cleanup
  • 🔒 Security fix

🧪 Testing

  • Manual testing completed
  • Functionality verified in development environment
  • No breaking changes introduced
  • Tested with different connection types (if applicable)

📸 Screenshots (if applicable)

N/A

✅ Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have manually tested my changes thoroughly
  • I have verified the changes work with different scenarios
  • Any dependent changes have been merged and published

📝 Additional Notes

The client.logout() call can throw when the WebSocket is already closed (e.g. after a network drop). Previously this would leave the instance in an inconsistent state in the database. The new flow ensures the database record always reflects connectionStatus: 'close' regardless of whether the Baileys client was reachable during logout.

Summary by Sourcery

Improve reliability and safety of WhatsApp instance logout and connection handling.

Bug Fixes:

  • Ensure logout flow sets the session to closed even if the client is already disconnected or logout fails.
  • Prevent reconnection attempts after specific disconnect status codes, including request timeouts (408).
  • Avoid crashes when the connection opens before the client user object is populated by skipping processing in that case.

Enhancements:

  • Always persist the instance connection status as closed in the database after logout to keep state consistent.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Apr 8, 2026

Reviewer's Guide

Improves the robustness of the WhatsApp Baileys logout and connection lifecycle handling by marking sessions as ended before teardown, hardening logout against already-closed clients, ensuring database connection status is updated on logout, preventing reconnection loops on timeout, and guarding against null user data on connection open.

Sequence diagram for the new logoutInstance flow

sequenceDiagram
  actor AdminUser
  participant ApiServer
  participant BaileysStartupService
  participant MessageProcessor as messageProcessor
  participant Client as client
  participant WebSocket as client_ws
  participant Prisma as prismaRepository
  participant Database as instanceTable

  AdminUser ->> ApiServer: Request logout of WhatsApp instance
  ApiServer ->> BaileysStartupService: logoutInstance()
  activate BaileysStartupService
  BaileysStartupService ->> BaileysStartupService: endSession = true
  BaileysStartupService ->> MessageProcessor: onDestroy()

  BaileysStartupService ->> Client: logout("Log out instance: " + instanceName)
  alt logout throws
    Client -->> BaileysStartupService: Error
    BaileysStartupService ->> BaileysStartupService: logger.warn(...)
  else logout succeeds
    Client -->> BaileysStartupService: resolved
  end

  BaileysStartupService ->> WebSocket: close()
  alt ws.close throws
    WebSocket -->> BaileysStartupService: Error (ignored)
  else ws.close succeeds
    WebSocket -->> BaileysStartupService: closed
  end

  BaileysStartupService ->> BaileysStartupService: stateConnection = { state: close, statusReason: 401 }

  BaileysStartupService ->> Prisma: session.delete({ sessionId: instanceId })
  Prisma ->> Database: delete session
  Database -->> Prisma: success

  BaileysStartupService ->> Prisma: instance.update({ id: instanceId, connectionStatus: close })
  Prisma ->> Database: update instance.connectionStatus = close
  Database -->> Prisma: success

  Prisma -->> BaileysStartupService: done
  deactivate BaileysStartupService
  BaileysStartupService -->> ApiServer: logout completed
  ApiServer -->> AdminUser: Logout successful
Loading

Class diagram for updated BaileysStartupService connection lifecycle handling

classDiagram
  class ChannelStartupService {
  }

  class BaileysStartupService {
    - boolean endSession
    - any messageProcessor
    - any client
    - any logger
    - any configService
    - any prismaRepository
    - any instance
    - string instanceId
    - string instanceName
    - string phoneNumber
    - any stateConnection

    + logoutInstance() Promise~void~
    + connectToWhatsapp(phoneNumber string) Promise~void~
    + connectionUpdate(connection string, lastDisconnect any) Promise~void~
    + getProfileName() Promise~string~
    + profilePicture(wuid string) Promise~string~
  }

  ChannelStartupService <|-- BaileysStartupService

  class PrismaRepository {
    + sessionDelete(sessionId string) Promise~void~
    + instanceUpdate(id string, connectionStatus string) Promise~void~
  }

  class Client {
    + logout(reason string) Promise~void~
    + wsClose() void
    + user any
  }

  class Instance {
    + string id
    + string wuid
    + string connectionStatus
  }

  BaileysStartupService o-- PrismaRepository : uses
  BaileysStartupService o-- Client : manages
  BaileysStartupService o-- Instance : updates
Loading

File-Level Changes

Change Details Files
Hardened logout flow to avoid crashes and ensure cleanup even when the Baileys client/WebSocket is already closed.
  • Set an internal endSession flag to true at the start of logout to suppress reconnection attempts after teardown.
  • Wrapped client.logout call in a try/catch and logged a warning on failure while still proceeding with cleanup.
  • Wrapped client.ws.close in a try/catch and ignored errors to tolerate already-closed sockets.
  • Explicitly set stateConnection to a closed state with statusReason 401 after logout/teardown.
  • Updated the related instance record in the database to set connectionStatus to 'close' after cleaning up sessions.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Adjusted reconnection logic and connection-open handling to avoid loops and crashes.
  • Added HTTP status code 408 to the codesToNotReconnect list so the service does not auto-reconnect on request-timeout disconnects.
  • Added a guard in the connection === 'open' handler to check for client.user?.id and early-return with a warning log if it is missing, preventing TypeError when Baileys fires open before user is populated.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Possibly linked issues

  • #: PR hardens logout and connection handling for 401/device_removed, directly targeting the reported connect-then-disconnect behavior.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In logoutInstance, consider handling or at least logging failures from the instance.update call so that DB write issues during logout are visible rather than silently failing after the state has been set to close in memory.
  • When setting this.stateConnection = { state: 'close', statusReason: 401 }, consider deriving the status code from the actual disconnect reason (similar to statusCode handling in connection === 'close') so the in-memory state more accurately reflects the underlying cause.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `logoutInstance`, consider handling or at least logging failures from the `instance.update` call so that DB write issues during logout are visible rather than silently failing after the state has been set to `close` in memory.
- When setting `this.stateConnection = { state: 'close', statusReason: 401 }`, consider deriving the status code from the actual disconnect reason (similar to `statusCode` handling in `connection === 'close'`) so the in-memory state more accurately reflects the underlying cause.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@daniloleonecarneiro daniloleonecarneiro changed the base branch from main to develop April 8, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant