Skip to content

PostgreSQL connection leak: a new sqlstore pool is created on instance reconnect #118

Description

@Talis-dev

Description

Evolution Go continuously creates new idle PostgreSQL connections in evogo_auth. The connections are not reused or closed after WhatsApp instance reconnects.

Over time, PostgreSQL reached its max_connections limit of 200 and started rejecting connections.

Environment

  • Evolution Go version: 0.7.2
  • Docker image: evoapicloud/evolution-go:0.7.2
  • Deployment: Docker
  • Database: PostgreSQL
  • POSTGRES_AUTH_DB: PostgreSQL database evogo_auth
  • POSTGRES_USERS_DB: PostgreSQL database evogo_users
  • Connected WhatsApp instances: 4
  • Created but disconnected instances: 1

Observed behavior

Immediately after restarting the Evolution Go container, PostgreSQL showed approximately:

evogo_users: 1 idle connection
evogo_auth: 7 idle connections

About 18 minutes later, evogo_auth had 11 idle connections and continued growing:

datname     | state | connections
------------+-------+------------
evogo_auth  | idle  | 11
evogo_users | idle  | 1

Before the restart, the same behavior eventually consumed all 200 PostgreSQL connection slots.

The new connections originate from the Evolution Go container. New evogo_auth connections appear after instance disconnect/reconnect cycles and remain idle.

Temporary mitigation

I configured:

ALTER ROLE <evolution_db_user>
IN DATABASE evogo_auth
SET idle_session_timeout = '5min';

After restarting Evolution Go, PostgreSQL began terminating the old idle connections after approximately five minutes. This prevents unlimited accumulation, but it does not fix the underlying pool lifecycle.

Suspected cause

StartClient creates a new Whatsmeow SQL store container for every client start:

container, err = sqlstore.New(
    context.Background(),
    "postgres",
    w.config.PostgresAuthDB,
    dbLog,
)

Source:

https://github.com/evolution-foundation/evolution-go/blob/main/pkg/whatsmeow/service/whatsmeow.go

When a Disconnected event occurs, ReconnectClient removes the client from the runtime maps and starts it again. However, the previously created sqlstore.Container is not retained by the service and is not closed.

Therefore, every reconnection may create another PostgreSQL pool while the previous pool remains open.

Expected behavior

  • PostgreSQL connections should be reused.
  • Reconnecting an instance should not permanently increase the number of idle database connections.
  • The number of PostgreSQL connections should be bounded by a shared pool, not by the number of reconnect attempts.
  • Hundreds or thousands of WhatsApp instances should not require one independent PostgreSQL pool per instance.

Suggested solution

Create one shared PostgreSQL sql.DB and one shared sqlstore.Container during application startup, using the Whatsmeow NewWithDB API.

Inject the shared container into whatsmeowService.

StartClient should only call:

container.GetDevice(...)

or:

container.NewDevice()

It should not call sqlstore.New() for every instance start.

The shared pool should be closed only during application shutdown.

If separate containers must remain, Evolution Go should retain and explicitly close each container before replacing or deleting a client.

Additional note

The v0.7.2 changelog mentions that the upstream Whatsmeow PostgreSQL pool patch was replaced by the application-side NewWithDB approach. However, StartClient still appears to use sqlstore.New() for each instance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions