June 14, 2020·4 min read·engineeringrqliteclusteringoperations

rqlite makes cluster join retries configurable

rqlite 5.4.0 exposes join attempt counts and intervals at startup. The implementation retries the configured address list in rounds, which matters when interpreting the settings.

A database node can start before the cluster endpoint it needs is available. A fixed retry policy then becomes part of whether the deployment can form its intended topology. rqlite 5.4.0 exposes the number of join attempts and the interval between them as startup options. The June 14 announcement describes this as the release's new capability.

The useful detail is how an attempt relates to several possible join addresses. The implementation walks the configured list, then waits before another round if none succeeds. An attempt count is therefore not necessarily the total count of HTTP requests. It controls an outer loop that can visit several endpoints and handle redirects within each endpoint's join operation.

I value rqlite's small deployment model, but startup timing still belongs to the distributed system. Configurable retry behavior helps express the environment's expected readiness delay in the node's own launch settings. It makes that policy visible without requiring every deployment wrapper to invent an external retry loop.

The launch options expose the existing policy

The server entry point in this release defines -join-attempts with a default of five and -join-interval with a default of five seconds. The -join option accepts a comma-delimited list of addresses. These settings are parsed before the server invokes the cluster join helper.

An illustrative launch gives a new node more retry rounds and a different interval. It assumes the addresses are reachable when the target processes become ready.

rqlited -node-id node-3 \
    -http-addr node3:4001 \
    -raft-addr node3:4002 \
    -join http://node1:4001,http://node2:4001 \
    -join-attempts 10 \
    -join-interval 3s \
    ~/node-3

The address list supplies candidate entry points into the cluster. The retry settings describe how persistently this startup operation tries them. Neither setting defines the cluster's voting majority or changes the role selected for the joining node. The join request still carries membership information to the existing cluster.

The entry point parses the interval as a duration and exits with an error if parsing fails. It passes the resulting duration and attempt count to the join helper. That is distinct from a total startup deadline. A duration between retry rounds does not include all the time spent resolving addresses and making requests.

One round visits the address list

The join implementation at the tag has an outer loop bounded by the attempt count and an inner loop over join addresses. It returns immediately when any address succeeds. If all addresses fail, it logs the failure and sleeps for the configured interval before continuing the outer loop.

For the illustrative list of two addresses, a failed round can try both. A success on the first address stops the process without needing to contact the second. The order therefore has practical meaning even though either endpoint may lead to the same cluster. The settings control a concrete sequential procedure, not parallel discovery across all possible members.

The code also sleeps after the last unsuccessful round before returning the final failure. This is a small detail, but it prevents reading the interval as a promise that applies only between additional attempts. The implementation's control flow determines the elapsed behavior. Multiplying an interval by an assumed number of gaps would omit request duration and could misdescribe the actual final wait.

The retry loop uses the same configured interval after each failed round. It does not implement exponential backoff in this version. Choosing a longer duration changes that repeated delay, while choosing more attempts changes how many rounds the helper permits before returning failure.

A candidate can redirect to the leader

Within an individual join operation, the helper posts the node ID, resolved Raft address, voting role and metadata. A permanent redirect replaces the endpoint with the supplied location and continues the operation. A successful response completes the join. This lets a candidate address act as an entry point even when it is not the current leader.

The helper requires a node ID and resolves the joining node's Raft address before posting. Increasing retry persistence does not make missing identity or an unusable advertised address correct. Such failures can repeat until the configured count is exhausted. The options let the environment tolerate temporary conditions, while the membership inputs still need valid meanings.

After all rounds fail, the helper returns ErrJoinFailed, and the server entry point treats the failed cluster join as fatal. The new controls therefore adjust how long this startup procedure persists before reporting failure. They do not silently convert the node into a successfully joined member when no request succeeded.

I prefer that finite outcome for a configured join. A launch command describes both the intended cluster entry points and the retry policy, while exhaustion remains an error the process supervisor can observe. A successful join has a specific endpoint and response, rather than being inferred from the mere fact that a database process is still running.