# Replaying Slots with Solana yellowstone gRPCs

Reconnect mechanisms are important for production applications — we don’t want to miss any data due to temporary network issues. But sometimes, <mark style="color:yellow;">reconnecting</mark> alone <mark style="color:yellow;">isn’t enough</mark>. We also need to <mark style="color:yellow;">replay data from a specific slot</mark>, especially if a stream drops during critical updates. Yellowstone gRPC supports this via the `fromSlot` field in the subscription request. By storing the last received slot and including it in the next subscription, you can ensure your stream resumes from where it left off — without missing a single block or transaction.

{% hint style="success" %}
At any given time, the earliest available slot for replay is approximately **150 slots older than the current slot**.
{% endhint %}

The example below illustrates how you can replay from a specific slot upon disconnection. You can paste this code in Replit to see it in action, or simply run the Repl [code here](https://replit.com/@shyft-to/reconnecting-and-replaying-slots-for-yellowstone-grpc?v=1).

{% tabs %}
{% tab title="TypeScript" %}
{% code overflow="wrap" %}

```typescript
import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
import { SubscribeRequest } from "@triton-one/yellowstone-grpc/dist/types/grpc/geyser";
import base58 from "bs58";

const GRPC_URL = "https://grpc.ams.shyft.to"; //enter your grpc url here
const X_TOKEN = ""; //enter your grpc access token here
const MAX_RETRY_WITH_LAST_SLOT = 30;
const RETRY_DELAY_MS = 1000;
const ADDRESS_TO_STREAM_FROM = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";

type StreamResult = {
  lastSlot?: string;
  hasRcvdMSg: boolean;
};

async function handleStream(
  client: Client,
  args: SubscribeRequest,
  lastSlot?: string,
): Promise<StreamResult> {
  const stream = await client.subscribe();
  let hasRcvdMSg = false;

  return new Promise((resolve, reject) => {
    stream.on("data", (data) => {
      const tx = data.transaction?.transaction?.transaction;
      if (tx?.signatures?.[0]) {
        const sig = base58.encode(tx.signatures[0]);
        console.log("Got tx:", sig);
        lastSlot = data.transaction.slot;
        hasRcvdMSg = true;
      }
    });

    stream.on("error", (err) => {
      stream.end();
      reject({ error: err, lastSlot, hasRcvdMSg });
    });

    const finalize = () => resolve({ lastSlot, hasRcvdMSg });
    stream.on("end", finalize);
    stream.on("close", finalize);

    stream.write(args, (err: any) => {
      if (err) reject({ error: err, lastSlot, hasRcvdMSg });
    });
  });
}

async function subscribeCommand(client: Client, args: SubscribeRequest) {
  let lastSlot: string | undefined;
  let retryCount = 0;

  while (true) {
    try {
      // checks if the stream is starting from a specific slot
      if (args.fromSlot) {
        console.log("Starting stream from slot", args.fromSlot);
      }
      // starts the stream from lastSlot if value is present
      const result = await handleStream(client, args, lastSlot);
      lastSlot = result.lastSlot;
      if (result.hasRcvdMSg) retryCount = 0;
    } catch (err: any) {
      console.error(
        `Stream error, retrying in ${RETRY_DELAY_MS / 1000} second...`,
      );
      //in case the stream is interrupted, it waits for a while before retrying
      await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));

      lastSlot = err.lastSlot;
      if (err.hasRcvdMSg) retryCount = 0;

      if (lastSlot && retryCount < MAX_RETRY_WITH_LAST_SLOT) {
        console.log(
          `#${retryCount} retrying with last slot ${lastSlot}, remaining retries ${
            MAX_RETRY_WITH_LAST_SLOT - retryCount
          }`,
        );
        // sets the fromSlot to the last slot received before the stream was interrupted, if it exists
        args.fromSlot = lastSlot;
        retryCount++;
      } else {
        //when there is no last slot available, it starts the stream from the latest slot
        console.log("Retrying from latest slot (no last slot available)");
        delete args.fromSlot;
        retryCount = 0;
        lastSlot = undefined;
      }
    }
  }
}

const client = new Client(GRPC_URL, X_TOKEN, {
  "grpc.keepalive_permit_without_calls": 1,
  "grpc.keepalive_time_ms": 10000,
  "grpc.keepalive_timeout_ms": 1000,
  "grpc.default_compression_algorithm": 2,
});

const req: SubscribeRequest = {
  accounts: {},
  slots: {},
  transactions: {
    pumpFun: {
      vote: false,
      failed: false,
      accountInclude: [ADDRESS_TO_STREAM_FROM],
      accountExclude: [],
      accountRequired: [],
    },
  },
  transactionsStatus: {},
  blocks: {},
  blocksMeta: {},
  entry: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.CONFIRMED,
};

subscribeCommand(client, req);
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="success" %}
The complete code of implementing a reconnection mechanism is available on [GitHub ](https://github.com/Shyft-to/solana-defi/tree/main/general-grpc-examples/Typescript/add_a_reconnect_mechanism)and [Replit here](https://replit.com/@shyft-to/reconnecting-and-replaying-slots-for-yellowstone-grpc#index.ts).
{% endhint %}

The above example implements a robust mechanism to **reconnect to the gRPC stream** and **replay from the last known slot** to avoid missing any data.

* **Reconnection**:\
  If the stream encounters an error (like a network drop), the stream automatically retries after waiting a short time (denoted by the`RETRY_DELAY_MS` variable). This loop ensures the stream keeps trying to reconnect without manual restart.
* **Replay from Last Slot**:\
  Before each retry, the app checks if it previously received any transaction data. If so, it stores the latest `slot` number (`lastSlot`). When reconnecting, it includes this `lastSlot` in the `fromSlot` field of the `SubscribeRequest`, telling Yellowstone gRPC to resume streaming **from that exact slot**, not from the current blockchain tip.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.shyft.to/solana-yellowstone-grpc/docs/getting-started/replaying-slots-with-grpc.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
