Skip to content

How to connect to a high-availability cluster

Through this guide, you will learn how to use GQLAlchemy to connect to a Memgraph high-availability (HA) cluster with client-side routing: you point GQLAlchemy at a coordinator and it routes each query to the right data instance — writes to the main, reads to a replica.

If you have any more questions, join our community and ping us on Discord.

Info

High availability is a Memgraph Enterprise feature, so you need a running HA cluster (coordinators and data instances) to use the features below. Client-side routing requires pymgclient>=1.6.0, which GQLAlchemy depends on. If you're unsure how to run an HA cluster, check out the Memgraph high-availability documentation.

Route a client through a coordinator

Create a Memgraph client with routing=True and point its host/port at a cluster coordinator rather than a specific data instance. GQLAlchemy fetches the cluster topology from the coordinator and routes queries accordingly:

from gqlalchemy import Memgraph

db = Memgraph(host="coordinator-1", port=7687, routing=True)

# Routed to the main.
db.execute("MERGE (:Person {name: 'Ada'})")

# Also routed to the main (the default access mode serves both reads and writes).
for result in db.execute_and_fetch("MATCH (n:Person) RETURN n.name AS name"):
    print(result["name"])

With routing=False (the default) GQLAlchemy connects directly to the given host/port, exactly as before.

Choose an access mode

access_mode selects which instance a routed client connects to: "WRITE" (the default) targets the main, "READ" targets a replica. You can pass the string or the mgclient constant:

from gqlalchemy import Memgraph

# A read-only client, routed to a replica.
reader = Memgraph(host="coordinator-1", port=7687, routing=True, access_mode="READ")
for result in reader.execute_and_fetch("MATCH (n:Person) RETURN count(n) AS count"):
    print(result["count"])
import mgclient
from gqlalchemy import Memgraph

writer = Memgraph(
    host="coordinator-1",
    port=7687,
    routing=True,
    access_mode=mgclient.ACCESS_MODE_WRITE,
)

Info

A routed client opens its connection to whichever instance was current when it connected. To keep working through a failover — where the main changes — use the managed transactions described below, which re-route and retry automatically.

Run managed transactions

For failover-safe operations, use execute_write() and execute_read(). Each takes a work callable that receives a transaction object exposing the usual execute / execute_and_fetch; the transaction is routed (writes to the main, reads to a replica), committed for you, and retried automatically if the cluster is briefly in flux (for example while a new main is being elected). Whatever work returns is returned to you:

from gqlalchemy import Memgraph

db = Memgraph(host="coordinator-1", port=7687, routing=True)

def add_person(tx):
    tx.execute("MERGE (:Person {name: $name})", {"name": "Ada"})
    rows = list(tx.execute_and_fetch("MATCH (n:Person) RETURN count(n) AS count"))
    return rows[0]["count"]

count = db.execute_write(add_person)

def count_people(tx):
    rows = list(tx.execute_and_fetch("MATCH (:Person) RETURN count(*) AS count"))
    return rows[0]["count"]

total = db.execute_read(count_people)

Warning

Because a managed transaction may run more than once on retry, make the work idempotent — use MERGE rather than CREATE so a re-run cannot duplicate a write. Materialize any results you need (e.g. wrap execute_and_fetch in list(...)) before returning them, since the transaction is closed once work returns.

Handle transient errors and tune retries

If a managed transaction cannot complete even after refreshing the routing table and exhausting its retries, GQLAlchemy raises GQLAlchemyTransientError — a subclass of GQLAlchemyDatabaseError, so existing error handling keeps working while letting you single out retryable failures:

from gqlalchemy import Memgraph, GQLAlchemyTransientError

db = Memgraph(host="coordinator-1", port=7687, routing=True)

try:
    db.execute_write(add_person)
except GQLAlchemyTransientError:
    # The cluster did not settle within the retry budget; surface or re-queue.
    raise

The retry budget is configurable on the client. Backoff is capped exponential — retry_backoff, 2 * retry_backoff, … up to retry_backoff_cap seconds:

db = Memgraph(
    host="coordinator-1",
    port=7687,
    routing=True,
    max_retries=8,
    retry_backoff=1.0,
    retry_backoff_cap=15.0,
)

Inspect the routing table

To see the topology the coordinator reports, use get_routing_table(). It returns a dict with ttl, write, read and route entries:

from gqlalchemy import Memgraph

db = Memgraph(host="coordinator-1", port=7687, routing=True)

table = db.get_routing_table()
print("main(s):", table["write"])
print("replica(s):", table["read"])
print("coordinator(s):", table["route"])

Hopefully, this guide has taught you how to connect to a Memgraph high-availability cluster using GQLAlchemy. If you have any more questions, join our community and ping us on Discord.