Skip to content

Load balance spurious read-only transactions to read replicas #925

@cannorin

Description

@cannorin

Is your feature request related to a problem? Please describe.

Some frameworks (for example, Strapi) wrap every query in an explicit transaction block:

https://github.com/strapi/strapi/blob/8c28a74d1219c09f4ee67402fd3a26f182c4990a/packages/core/core/src/services/document-service/repository.ts#L432-L447

With the current implementation of pgcat, any explicit transaction is pinned to the primary, so these read‑only transactions cannot be balanced to replicas and replica capacity remains unused.

Describe the solution you'd like

Stop assuming that every transaction is likely a write query, and treat it as read‑only until the first write statement is detected.

pgcat/src/query_router.rs

Lines 490 to 494 in 5b03881

// All transactions go to the primary, probably a write.
StartTransaction { .. } => {
self.active_role = Some(Role::Primary);
break;
}

This behavior needs not to be default, and could be enabled with a configuration.

Describe alternatives you've considered

Fixing the client implementation is ideal, but not always feasible when the codebase is proprietary or too large.

Additional context

pgpool-II (with statement_level_load_balance = on) actually has this feature:

https://www.pgpool.net/docs/latest/en/html/runtime-config-load-balancing.html

For a query to be load balanced, all the following requirements must be met:
...

  • the query must not be in an explicitly declared transaction (i.e. not in a BEGIN ~ END block)
    • However, if following conditions are met, load balance is possible even if in an explicit transaction
      • ...
      • transaction has not issued a write query yet

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