From eaf2f39fb1daf8152334f25da7b76f4df4ed9289 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Wed, 12 May 2021 16:37:17 +0530 Subject: [PATCH] added retries to urql --- packages/web/graphql/client.ts | 15 ++++++++++++++ packages/web/graphql/getPlayer.ts | 22 ++++++++++++++++---- packages/web/graphql/getPlayers.ts | 13 ++++++++++++ packages/web/package.json | 3 ++- packages/web/pages/player/[username].tsx | 4 ++-- packages/web/pages/players.tsx | 17 ++-------------- packages/web/pages/quest/[id].tsx | 10 +++++---- yarn.lock | 26 ++++++++++++++++-------- 8 files changed, 75 insertions(+), 35 deletions(-) diff --git a/packages/web/graphql/client.ts b/packages/web/graphql/client.ts index 96d5d7c8..e001b361 100644 --- a/packages/web/graphql/client.ts +++ b/packages/web/graphql/client.ts @@ -1,3 +1,4 @@ +import { retryExchange } from '@urql/exchange-retry'; import { initUrqlClient, NextComponentType, @@ -8,6 +9,7 @@ import React, { createElement } from 'react'; import { cacheExchange, Client, + CombinedError, createClient, dedupExchange, fetchExchange, @@ -17,9 +19,22 @@ import { import { CONFIG } from '../config'; import { getTokenFromStore } from '../lib/auth'; +const errorHasResponseTimeout = (err: CombinedError): boolean => + err.graphQLErrors.length > 0 && + !!err.graphQLErrors.find((_err) => _err.message === 'ResponseTimeout'); + export const client = createClient({ url: CONFIG.graphqlURL, suspense: false, + exchanges: [ + dedupExchange, + cacheExchange, + retryExchange({ + retryIf: (error) => + !!(errorHasResponseTimeout(error) || error.networkError), + }), + fetchExchange, + ], }); export const getSsrClient = (): [Client, ReturnType] => { diff --git a/packages/web/graphql/getPlayer.ts b/packages/web/graphql/getPlayer.ts index d90b5e63..2c720668 100644 --- a/packages/web/graphql/getPlayer.ts +++ b/packages/web/graphql/getPlayer.ts @@ -1,6 +1,10 @@ import gql from 'fake-tag'; -import { GetPlayerQuery, GetPlayerQueryVariables } from './autogen/types'; +import { + GetPlayerQuery, + GetPlayerQueryVariables, + PlayerFragmentFragment, +} from './autogen/types'; import { client } from './client'; import { PlayerFragment } from './fragments'; @@ -13,11 +17,21 @@ const playerQuery = gql` ${PlayerFragment} `; -export const getPlayer = async (username: string | undefined) => { +export const getPlayer = async ( + username: string | undefined, +): Promise => { if (!username) return null; - const { data } = await client + const { data, error } = await client .query(playerQuery, { username }) .toPromise(); - return data?.player[0]; + if (!data) { + if (error) { + throw error; + } + + return null; + } + + return data?.player?.length > 0 ? data.player[0] : null; }; diff --git a/packages/web/graphql/getPlayers.ts b/packages/web/graphql/getPlayers.ts index 294e934a..266df6e2 100644 --- a/packages/web/graphql/getPlayers.ts +++ b/packages/web/graphql/getPlayers.ts @@ -38,3 +38,16 @@ export const getPlayers = async ( return data.player; }; + +const LIMIT = 50; +const TOTAL_PLAYERS = 150; + +export const getTopPlayers = async (): Promise => { + const promises: Promise[] = new Array( + TOTAL_PLAYERS / LIMIT, + ) + .fill(false) + .map((_, i) => getPlayers(LIMIT, i * LIMIT)); + const playersArr = await Promise.all(promises); + return playersArr.reduce((_total, _players) => [..._total, ..._players], []); +}; diff --git a/packages/web/package.json b/packages/web/package.json index 009f1e5d..d032dcbe 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -14,6 +14,7 @@ "dependencies": { "@metafam/ds": "0.1.0", "@metafam/utils": "1.0.0", + "@urql/exchange-retry": "^0.2.1", "@walletconnect/web3-provider": "1.4.1", "copy-to-clipboard": "^3.3.1", "ethers": "5.1.4", @@ -33,7 +34,7 @@ "react-qr-svg": "^2.3.0", "spacetime": "6.16.0", "spacetime-informal": "0.6.1", - "urql": "2.0.2", + "urql": "2.0.3", "web3modal": "1.9.3" } } diff --git a/packages/web/pages/player/[username].tsx b/packages/web/pages/player/[username].tsx index e47dd22e..9e31b888 100644 --- a/packages/web/pages/player/[username].tsx +++ b/packages/web/pages/player/[username].tsx @@ -1,7 +1,7 @@ import { Box, Flex, LoadingState } from '@metafam/ds'; import { PlayerHero } from 'components/Player/Section/PlayerHero'; import { getPlayer } from 'graphql/getPlayer'; -import { getPlayers } from 'graphql/getPlayers'; +import { getTopPlayers } from 'graphql/getPlayers'; import { GetStaticPaths, GetStaticPropsContext, @@ -171,7 +171,7 @@ export default PlayerPage; type QueryParams = { username: string }; export const getStaticPaths: GetStaticPaths = async () => { - const players = await getPlayers(); + const players = await getTopPlayers(); return { paths: players.map(({ username }) => ({ diff --git a/packages/web/pages/players.tsx b/packages/web/pages/players.tsx index c6a02d7c..dd7599a1 100644 --- a/packages/web/pages/players.tsx +++ b/packages/web/pages/players.tsx @@ -1,26 +1,13 @@ import { PageContainer } from 'components/Container'; import { PlayerList } from 'components/PlayerList'; -import { PlayerFragmentFragment } from 'graphql/autogen/types'; -import { getPlayers } from 'graphql/getPlayers'; +import { getTopPlayers } from 'graphql/getPlayers'; import { InferGetStaticPropsType } from 'next'; import React from 'react'; type Props = InferGetStaticPropsType; -const LIMIT = 50; -const TOTAL_PLAYERS = 150; - export const getStaticProps = async () => { - const promises: Promise[] = new Array( - TOTAL_PLAYERS / LIMIT, - ) - .fill(false) - .map((_, i) => getPlayers(LIMIT, i * LIMIT)); - const playersArr = await Promise.all(promises); - const players = playersArr.reduce( - (_total, _players) => [..._total, ..._players], - [], - ); + const players = await getTopPlayers(); return { props: { players, diff --git a/packages/web/pages/quest/[id].tsx b/packages/web/pages/quest/[id].tsx index cd7118e5..e92a86c4 100644 --- a/packages/web/pages/quest/[id].tsx +++ b/packages/web/pages/quest/[id].tsx @@ -15,7 +15,11 @@ import { } from 'graphql/autogen/types'; import { getQuestWithCompletions } from 'graphql/getQuest'; import { getQuestIds } from 'graphql/getQuests'; -import { GetStaticPaths, GetStaticPropsContext } from 'next'; +import { + GetStaticPaths, + GetStaticPropsContext, + InferGetStaticPropsType, +} from 'next'; import { useRouter } from 'next/router'; import React, { useMemo } from 'react'; import { FaArrowLeft } from 'react-icons/fa'; @@ -28,9 +32,7 @@ import { getSsrClient } from '../../graphql/client'; import { useUser } from '../../lib/hooks'; import { canCompleteQuest } from '../../utils/questHelpers'; -type Props = { - quest_id: string; -}; +type Props = InferGetStaticPropsType; const QuestPage: React.FC = ({ quest_id }) => { const router = useRouter(); diff --git a/yarn.lock b/yarn.lock index d49d5c01..990adc33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6625,14 +6625,22 @@ "@typescript-eslint/types" "4.23.0" eslint-visitor-keys "^2.0.0" -"@urql/core@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@urql/core/-/core-2.0.0.tgz#b4936dd51fe84cb570506d9ee2579149689f7535" - integrity sha512-Qj24CG8ullqZZsYmjrSH0JhH+nY7kj8GbVbA9si3KUjlYs75A/MBQU3i97j6oWyGldDBapyis2CfaQeXKbv8rA== +"@urql/core@>=2.1.0", "@urql/core@^2.1.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@urql/core/-/core-2.1.1.tgz#106e3a5aa22bf9ec6ec5d55697f101a0aa50f114" + integrity sha512-eKEmrSjnXzgXJ4xqoHh7KGV0Xj3hsEeQydrVocOPlpcGhlo8+sqR1Eo8ChmGCdLL4hf4biBN4dG59s11cG0iRQ== dependencies: "@graphql-typed-document-node/core" "^3.1.0" wonka "^4.0.14" +"@urql/exchange-retry@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@urql/exchange-retry/-/exchange-retry-0.2.1.tgz#f4502b4b6762121fcc6a5971e85f273b8ec471bf" + integrity sha512-uYgXxLW/lDhUOfkoMSRcFB/kGCb49tcjmIX7uVC51YAtM0Ni2qRunOdtWkOncG2RVAzB54lOGuyP/ulmCiF0yg== + dependencies: + "@urql/core" ">=2.1.0" + wonka "^4.0.14" + "@vue/compiler-core@3.0.11": version "3.0.11" resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.11.tgz#5ef579e46d7b336b8735228758d1c2c505aae69a" @@ -27512,12 +27520,12 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" -urql@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/urql/-/urql-2.0.2.tgz#53e8f22747eff4550e46b9bbc8b44aa9c6de3e68" - integrity sha512-ku5lT0vq7Efpd6Mg1r40C/z39GbGxFtuK2+le26+v125cQL7OVGzE2XzG3jSiHa5m6abCoZO9xS6N2QIfoJ/gg== +urql@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/urql/-/urql-2.0.3.tgz#41bc4ad3ea7a1c995bbc8002f9ee82af1396bd26" + integrity sha512-CEfCsODKbAloDuAaT3NeMvibKpWxfS86DucI/HGam9uuqiZLpunuKb4p9+SWwoWLRf6Q1kUeQKGZoI5GqudOCg== dependencies: - "@urql/core" "^2.0.0" + "@urql/core" "^2.1.0" wonka "^4.0.14" ursa-optional@^0.10.1, ursa-optional@~0.10.0: