> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blockdb.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Connection Management

> Heartbeats, timeouts, reconnection, and backpressure best practices for BlockDB WSS clients.

## Heartbeats (ping/pong)

BlockDB sends periodic WebSocket `ping` frames. Clients must respond with `pong` to keep the connection alive.

<Note>
  Most WebSocket libraries handle `ping`/`pong` automatically. If yours does not, enable keepalives or implement `pong` responses.
</Note>

## Idle timeout

Connections with no active subscriptions (or missing heartbeat responses) may be terminated after an idle period.

* **Recommendation**: subscribe soon after connecting and keep `ping`/`pong` enabled.
* **If you intentionally idle**: close the socket gracefully and reconnect when needed.

## Reconnection strategy

You should assume transient disconnects (network, deploys, backpressure). Use exponential backoff with jitter:

* 1s → 2s → 4s → 8s … (cap at \~30s)
* add random jitter (e.g., ±20%)

<CodeGroup>
  ```bash bash theme={null}
  # Reconnect loop with exponential backoff (cap 30s).
  # Note: wscat is interactive; when the socket closes, the command exits and the loop retries.
  attempt=0
  while true; do
    delay=$((2 ** attempt))
    if [ "$delay" -gt 30 ]; then delay=30; fi

    echo "Connecting (attempt=$attempt)..."
    wscat -c wss://api.blockdb.io/v1/evm/ \
      -H "Authorization: Bearer $BLOCKDB_API_KEY" \
      -x '{"action":"subscribe","chain_id":1,"dataset_id":"0101","params":{}}'

    echo "Disconnected. Sleeping ${delay}s..."
    sleep "$delay"
    attempt=$((attempt + 1))
  done
  ```

  ```c C theme={null}
  // Sketch: reconnect with backoff and resubscribe (pseudocode-ish)
  #include <stdio.h>
  #include <unistd.h>

  int main(void) {
      int attempt = 0;
      for (;;) {
          int delay = 1 << attempt;
          if (delay > 30) delay = 30;

          // connect_ws("wss://api.blockdb.io/v1/evm/");
          // send("{\"action\":\"subscribe\",\"chain_id\":1,\"dataset_id\":\"0101\",\"params\":{}}");
          // while (connected) { read_messages(); }

          fprintf(stderr, "disconnected; retrying in %ds\n", delay);
          sleep(delay);
          attempt++;
      }
  }
  ```

  ```csharp .NET theme={null}
  using System;
  using System.Net.WebSockets;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;

  class Program {
      static async Task Main() {
          var subMsg = "{\"action\":\"subscribe\",\"chain_id\":1,\"dataset_id\":\"0101\",\"params\":{}}";

          for (var attempt = 0; ; attempt++) {
              var delayMs = Math.Min(30_000, (int)(1000 * Math.Pow(2, attempt)));
              try {
                  using var ws = new ClientWebSocket();
                  ws.Options.SetRequestHeader("Authorization", $"Bearer {Environment.GetEnvironmentVariable(\"BLOCKDB_API_KEY\")}");
                  await ws.ConnectAsync(new Uri("wss://api.blockdb.io/v1/evm/"), CancellationToken.None);

                  await ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(subMsg)), WebSocketMessageType.Text, true, CancellationToken.None);

                  var buffer = new byte[1024 * 32];
                  while (ws.State == WebSocketState.Open) {
                      var res = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                      if (res.MessageType == WebSocketMessageType.Close) break;
                      Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, res.Count));
                  }
              } catch (Exception ex) {
                  Console.WriteLine(ex.Message);
              }

              await Task.Delay(delayMs);
          }
      }
  }
  ```

  ```python Python theme={null}
  # pip install websocket-client
  import json
  import os
  import random
  import time
  import websocket

  SUB = {"action": "subscribe", "chain_id": 1, "dataset_id": "0101", "params": {}}

  def run_once():
      def on_open(ws):
          ws.send(json.dumps(SUB))

      def on_message(ws, message):
          # Handle subscribe_response/unsubscribe_response/update
          print(message)

      ws = websocket.WebSocketApp(
          "wss://api.blockdb.io/v1/evm/",
          header={"Authorization": f"Bearer {os.getenv('BLOCKDB_API_KEY')}"},
          on_open=on_open,
          on_message=on_message,
      )
      ws.run_forever()

  attempt = 0
  while True:
      run_once()
      base = min(30, 2 ** attempt)
      time.sleep(base * (0.8 + random.random() * 0.4))
      attempt += 1
  ```

  ```javascript Node.js theme={null}
  const WebSocket = require('ws');

  const URL = 'wss://api.blockdb.io/v1/evm/';
  const SUBS = [
    { action: 'subscribe', chain_id: 1, dataset_id: '0101', params: {} }
  ];

  function connect(attempt = 0) {
    const ws = new WebSocket(URL, {
      headers: { Authorization: `Bearer ${process.env.BLOCKDB_API_KEY}` }
    });

    ws.on('open', () => {
      attempt = 0;
      for (const msg of SUBS) ws.send(JSON.stringify(msg));
    });

    ws.on('message', (data) => {
      // Handle subscribe_response/unsubscribe_response/update
      // Keep this handler fast; offload heavy work.
    });

    ws.on('close', () => {
      const base = Math.min(30_000, 1000 * 2 ** attempt);
      const jitter = base * (0.8 + Math.random() * 0.4);
      setTimeout(() => connect(attempt + 1), jitter);
    });
  }

  connect();
  ```

  ```go Go theme={null}
  package main

  import (
  	"log"
  	"math/rand"
  	"net/http"
  	"os"
  	"time"

  	"github.com/gorilla/websocket"
  )

  func main() {
  	sub := []byte(`{"action":"subscribe","chain_id":1,"dataset_id":"0101","params":{}}`)

  	for attempt := 0; ; attempt++ {
  		header := http.Header{"Authorization": []string{"Bearer " + os.Getenv("BLOCKDB_API_KEY")}}
  		c, _, err := websocket.DefaultDialer.Dial("wss://api.blockdb.io/v1/evm/", header)
  		if err != nil {
  			sleepWithBackoff(attempt)
  			continue
  		}

  		_ = c.WriteMessage(websocket.TextMessage, sub)
  		for {
  			_, msg, err := c.ReadMessage()
  			if err != nil {
  				break
  			}
  			log.Printf("%s\n", msg)
  		}
  		_ = c.Close()
  		sleepWithBackoff(attempt)
  	}
  }

  func sleepWithBackoff(attempt int) {
  	base := 1 << attempt
  	if base > 30 {
  		base = 30
  	}
  	jitter := 0.8 + rand.Float64()*0.4
  	time.Sleep(time.Duration(float64(base)*jitter) * time.Second)
  }
  ```
</CodeGroup>

## Resubscribe after reconnect

The WebSocket connection state is not preserved across reconnects. Maintain a local list of active subscriptions and re-send `subscribe` messages after `open`.

For data continuity and reconciliation (especially around reorgs), see: [Reliability & Reorgs](/wss-reference/overview/reliability-and-reorgs).

## Backpressure & rate control

If the server cannot deliver messages fast enough (or your client cannot process them fast enough), the connection may be closed to protect the system.

* Common signal: **close code 1013 `TRY_AGAIN_LATER`**
* What to do:
  * reconnect with **longer backoff** (and jitter)
  * **reduce** subscription count
  * add or tighten **filters** (`params`) on high-volume streams
  * move heavy processing off the receive loop

See: [WSS Error Codes](/troubleshooting/error-codes/wss/home)

## Logging & support

When debugging connection stability, always log:

* close code + reason (if provided)
* timestamp (UTC)
* the last `subscribe` message(s) you sent (redact API key)

## See also

* [Quickstart](/wss-reference/overview/quickstart)
* [Errors](/wss-reference/overview/errors)
* [Runbook · WSS Connection Issues](/troubleshooting/runbooks/wss-connection-issues)
* [WSS Error Codes](/troubleshooting/error-codes/wss/home)
