Browse Source

pause asset resolution when providers are being fetched (#1138)

Klaudiusz Dembler 3 năm trước cách đây
mục cha
commit
ac8267d42e

+ 9 - 3
src/api/hooks/workers.ts

@@ -22,15 +22,21 @@ export const useWorker = (id: string, opts?: WorkerOpts) => {
 }
 
 type WorkersOpts = QueryHookOptions<GetWorkersQuery>
+export const storageWorkersVariables: GetWorkersQueryVariables = {
+  where: {
+    metadata_contains: 'http',
+    isActive_eq: true,
+    type_eq: WorkerType.Storage,
+  },
+}
 export const useStorageWorkers = (variables: GetWorkersQueryVariables, opts?: WorkersOpts) => {
   const { data, loading, ...rest } = useGetWorkersQuery({
     ...opts,
     variables: {
+      ...storageWorkersVariables,
       ...variables,
       where: {
-        metadata_contains: 'http',
-        isActive_eq: true,
-        type_eq: WorkerType.Storage,
+        ...storageWorkersVariables.where,
         ...variables.where,
       },
     },

+ 3 - 2
src/providers/assets/assetsManager.tsx

@@ -25,8 +25,9 @@ export const AssetsManager: React.FC = () => {
       addAssetBeingResolved(contentId)
 
       const resolutionData = pendingAssets[contentId]
-      const allStorageProviders = shuffle(getStorageProviders() || [])
-      const storageProvidersWithoutLiaison = allStorageProviders.filter(
+      const storageProviders = await getStorageProviders()
+      const shuffledStorageProviders = shuffle(storageProviders)
+      const storageProvidersWithoutLiaison = shuffledStorageProviders.filter(
         (provider) => provider.id !== resolutionData.dataObject?.liaison?.id
       )
       const liaison = resolutionData.dataObject?.liaison

+ 42 - 30
src/providers/storageProviders.tsx

@@ -1,13 +1,21 @@
-import React, { SetStateAction, useCallback, useContext, useState } from 'react'
-
-import { useStorageWorkers as useStorageProvidersData } from '@/api/hooks'
-import { BasicWorkerFieldsFragment } from '@/api/queries/__generated__/workers.generated'
+import { ApolloQueryResult, useApolloClient } from '@apollo/client'
+import React, { SetStateAction, useCallback, useContext, useEffect, useState } from 'react'
+import { useRef } from 'react'
+
+import { storageWorkersVariables } from '@/api/hooks'
+import {
+  BasicWorkerFieldsFragment,
+  GetWorkersDocument,
+  GetWorkersQuery,
+  GetWorkersQueryVariables,
+} from '@/api/queries/__generated__/workers.generated'
 import { Logger } from '@/utils/logger'
 import { getRandomIntInclusive } from '@/utils/number'
 
+type StorageProvidersPromise = Promise<ApolloQueryResult<GetWorkersQuery>>
+
 type StorageProvidersContextValue = {
-  storageProviders: BasicWorkerFieldsFragment[]
-  storageProvidersLoading: boolean
+  storageProvidersPromiseRef: React.MutableRefObject<StorageProvidersPromise | undefined>
   notWorkingStorageProvidersIds: string[]
   setNotWorkingStorageProvidersIds: React.Dispatch<SetStateAction<string[]>>
 }
@@ -29,20 +37,27 @@ class NoStorageProviderError extends Error {
 // ¯\_(ツ)_/¯ for the name
 export const StorageProvidersProvider: React.FC = ({ children }) => {
   const [notWorkingStorageProvidersIds, setNotWorkingStorageProvidersIds] = useState<string[]>([])
+  const storageProvidersPromiseRef = useRef<StorageProvidersPromise>()
 
-  const { storageProviders, loading } = useStorageProvidersData(
-    { limit: 100 },
-    {
+  const client = useApolloClient()
+
+  useEffect(() => {
+    const promise = client.query<GetWorkersQuery, GetWorkersQueryVariables>({
+      query: GetWorkersDocument,
       fetchPolicy: 'network-only',
-      onError: (error) => Logger.error('Failed to fetch storage providers list', error),
-    }
-  )
+      variables: {
+        ...storageWorkersVariables,
+        limit: 100,
+      },
+    })
+    storageProvidersPromiseRef.current = promise
+    promise.catch((error) => Logger.error('Failed to fetch storage providers list', error))
+  }, [client])
 
   return (
     <StorageProvidersContext.Provider
       value={{
-        storageProvidersLoading: loading,
-        storageProviders: storageProviders || [],
+        storageProvidersPromiseRef: storageProvidersPromiseRef,
         notWorkingStorageProvidersIds,
         setNotWorkingStorageProvidersIds,
       }}
@@ -59,19 +74,16 @@ export const useStorageProviders = () => {
     throw new Error('useStorageProviders must be used within StorageProvidersProvider')
   }
 
-  const {
-    storageProvidersLoading,
-    storageProviders,
-    notWorkingStorageProvidersIds,
-    setNotWorkingStorageProvidersIds,
-  } = ctx
-
-  const getStorageProviders = useCallback(() => {
-    // make sure we finished fetching providers list
-    if (storageProvidersLoading) {
-      // TODO: we need to handle that somehow, possibly make it async and block until ready
-      Logger.error('Trying to use storage providers while still loading')
-      return null
+  const { storageProvidersPromiseRef, notWorkingStorageProvidersIds, setNotWorkingStorageProvidersIds } = ctx
+
+  const getStorageProviders = useCallback(async () => {
+    let storageProviders: BasicWorkerFieldsFragment[] = []
+    try {
+      const storageProvidersData = await storageProvidersPromiseRef.current
+      storageProviders = storageProvidersData?.data.workers || []
+    } catch {
+      // error is handled by the context
+      return []
     }
 
     const workingStorageProviders = storageProviders.filter(
@@ -87,10 +99,10 @@ export const useStorageProviders = () => {
     }
 
     return workingStorageProviders
-  }, [notWorkingStorageProvidersIds, storageProviders, storageProvidersLoading])
+  }, [notWorkingStorageProvidersIds, storageProvidersPromiseRef])
 
-  const getRandomStorageProvider = useCallback(() => {
-    const workingStorageProviders = getStorageProviders()
+  const getRandomStorageProvider = useCallback(async () => {
+    const workingStorageProviders = await getStorageProviders()
     if (!workingStorageProviders) {
       return null
     }

+ 1 - 1
src/providers/uploadsManager/useStartFileUpload.tsx

@@ -82,7 +82,7 @@ export const useStartFileUpload = () => {
     async (file: File | Blob | null, asset: InputAssetUpload, opts?: StartFileUploadOptions) => {
       let storageUrl: string, storageProviderId: string
       try {
-        const storageProvider = getRandomStorageProvider()
+        const storageProvider = await getRandomStorageProvider()
         if (!storageProvider) {
           return
         }