From 4437ccb2346da0bcb7febced5793c24618c0cc4c Mon Sep 17 00:00:00 2001 From: Daniel Padrino Date: Fri, 24 Jul 2026 16:20:10 -0300 Subject: [PATCH] Retry transient Ponder GraphQL network errors The GetPositionsV2 sync job occasionally sees a "Premature close" from the indexer, consistent with a stale keep-alive socket being reused right as it's closed server-side. The existing fallback path only retries when the fallback URL differs from the primary, and in this deployment they're intentionally the same host, so every occurrence went straight to the logs with nothing more attempted. Adds a RetryLink ahead of the HTTP link so transport-level failures get a few short, jittered retries before reaching the error/fallback handling, independent of how primary/fallback are configured. GraphQL-level errors are unaffected. --- api.apollo.config.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/api.apollo.config.ts b/api.apollo.config.ts index c2af9ef..6be4354 100644 --- a/api.apollo.config.ts +++ b/api.apollo.config.ts @@ -1,5 +1,6 @@ import { ApolloClient, ApolloLink, createHttpLink, InMemoryCache } from '@apollo/client/core'; import { onError } from '@apollo/client/link/error'; +import { RetryLink } from '@apollo/client/link/retry'; import { Logger } from '@nestjs/common'; import fetch from 'cross-fetch'; import { CONFIG } from './api.config'; @@ -57,6 +58,14 @@ const errorLink = onError(({ graphQLErrors, networkError, operation, forward }) } }); +// Retries transport-level failures (e.g. a stale keep-alive socket closing +// mid-response) before they reach errorLink, so a one-off blip self-heals +// instead of tripping the fallback/error path. +const retryLink = new RetryLink({ + delay: { initial: 200, max: 2000, jitter: true }, + attempts: { max: 3, retryIf: (error) => !!error }, +}); + const httpLink = createHttpLink({ uri: (operation) => operation.getContext().targetUrl ?? getIndexerUrl(), fetch: (uri: RequestInfo | URL, options?: RequestInit) => { @@ -74,7 +83,7 @@ const httpLink = createHttpLink({ }, }); -const link = ApolloLink.from([errorLink, routingLink, httpLink]); +const link = ApolloLink.from([errorLink, routingLink, retryLink, httpLink]); export const PONDER_CLIENT = new ApolloClient({ link,