Reliable connections

The rews (reliable WebSocket) package wraps a standard WebSocket connection and adds automatic reconnection when the connection is lost. On reconnect, it restores the previous session state including namespace, database, authentication, variables, and live queries.

This is useful for long-running applications that need to survive transient network failures without manual reconnection logic.

API References

FunctionDescription
rews.New(newConn, interval, unmarshaler, logger)Creates a new auto-reconnecting WebSocket connection
rews.NewExponentialBackoffRetryer()Creates a retryer with exponential backoff and jitter
rews.NewFixedDelayRetryer(delay, maxRetries)Creates a retryer with a fixed delay between attempts

Setting up a reliable connection

Create a rews.Connection by providing a factory function that constructs the underlying WebSocket connection, a check interval for detecting disconnections, a CBOR unmarshaler, and an optional logger.

import (
"context"
"net/url"
"time"

surrealdb "github.com/surrealdb/surrealdb.go"
"github.com/surrealdb/surrealdb.go/contrib/rews"
"github.com/surrealdb/surrealdb.go/pkg/connection"
"github.com/surrealdb/surrealdb.go/pkg/connection/gorillaws"
"github.com/surrealdb/surrealdb.go/surrealcbor"
)

endpoint, _ := url.Parse("ws://localhost:8000/rpc")
codec := surrealcbor.New()

conn := rews.New(
func(ctx context.Context) (*gorillaws.WebSocket, error) {
conf := connection.NewConfig(endpoint)
conf.Marshaler = codec
conf.Unmarshaler = codec
return gorillaws.New(conf), nil
},
5*time.Second,
codec,
nil,
)

Then pass the connection to FromConnection to create a *DB:

db, err := surrealdb.FromConnection(ctx, conn)
if err != nil {
log.Fatal(err)
}
defer db.Close(ctx)

Configuring retry behavior

By default, connection attempts are not retried. Set the Retryer field to enable automatic retries on connection failure.

The ExponentialBackoffRetryer increases the delay between retries exponentially, with optional jitter to avoid thundering herd problems:

retryer := rews.NewExponentialBackoffRetryer()
retryer.MaxRetries = 10
retryer.InitialDelay = 1 * time.Second
retryer.MaxDelay = 30 * time.Second
conn.Retryer = retryer
FieldDefaultDescription
InitialDelay1sDelay before the first retry
MaxDelay30sMaximum delay between retries
Multiplier2.0Exponential backoff multiplier
MaxRetries0 (infinite)Maximum retry attempts, 0 for unlimited
JittertrueAdd randomness to avoid synchronized retries
JitterFactor0.3Maximum jitter as a fraction of the delay

For simpler cases, FixedDelayRetryer uses a constant delay:

conn.Retryer = rews.NewFixedDelayRetryer(2*time.Second, 5)

You can also implement the Retryer interface for custom strategies:

type Retryer interface {
NextDelay(attempt int, lastErr error) (time.Duration, bool)
Reset()
}

What gets restored on reconnect

When the connection is lost and re-established, rews automatically restores:

  1. Namespace and database -- the last values passed to .Use()

  2. Authentication -- the last token from .SignIn(), .SignUp(), or .Authenticate()

  3. Connection variables -- all variables set with .Let() (and removed with .Unset())

  4. Live queries -- all active live queries are re-subscribed, and notification routing is restored

Connection states

The rews.Connection tracks its state through a state machine:

StateDescription
DisconnectedNot connected, initial state
ConnectingConnection attempt in progress
ConnectedConnection established and active
ClosingClose requested, shutting down
ClosedFully closed, cannot be reused

Learn more