Не удается загрузить файл в исходную группу Azure Front Door из-за задержки?

Я застрял в этой проблеме в течение двух дней.

Я добавил 4 источника хранения BLOB-объектов в одну группу источников у входной двери Azure. Я провожу пробную версию токенов Blob Sas.

Я не обновлял какие-либо настройки, такие как веса и приоритет, проверки работоспособности включены. Пожалуйста, скажите мне, что я делаю неправильно.

Код по запросу:

Извините за немного неаккуратный код, потому что я очень спешил.

Расчет задержки при входе пользователя:

import { azurePingContainers } from "@/constants/azure-containers";
import axios from "axios";

export async function checkAzureLatency() {
    const response = await Promise.all(azurePingContainers.map(container => {
        return new Promise<{ latency: number, account: string }>((resolve) => {
            const startTime = performance.now();
            axios.get(container.url)
                .then(() => {
                    const endTime = performance.now();
                    let latency = endTime - startTime;
                    console.info(`${container.account} latency: ${latency}ms`);
                    latency = parseFloat(latency.toFixed(2));
                    resolve({ latency, account: container.account });
                })
                .catch(error => {
                    console.error(`Error fetching ${container.account} latency: ${error}`);
                    resolve({ latency: Infinity, account: container.account });
                });

        })
    }))
    const validResponses = response.filter(result => result.latency !== Infinity)
    if (validResponses.length === 0) {
        return null;
    }
    return validResponses.sort((a, b) => a.latency - b.latency)
}


export async function averageLatency() {
    const latencyChecks = (await Promise.all([
        checkAzureLatency(),
        checkAzureLatency(),
        checkAzureLatency()
    ])).filter(result => result !== null)
    if (latencyChecks.length === 0) {
        return null
    }
    console.info(latencyChecks)
    const totalLatencyArray = latencyChecks.reduce((acc, val) => {
        val.forEach((current) => {
            const sameValue = acc.findIndex((x) => x.account === current.account)
            if (sameValue>-1) {
                acc[sameValue] = {latency: parseFloat((current.latency + acc[sameValue].latency).toFixed(2)) ,account: current.account}
            } else {
                acc.push(current)
            }
        })
        return acc
    }, [])
    console.info('totalLatencyArray', totalLatencyArray)
    const averageLatencyArray = totalLatencyArray.map(item => ({
        latency: parseFloat((item.latency / latencyChecks.length).toFixed(2)),
        account: item.account
    }));
    console.info(averageLatencyArray)
    localStorage.setItem('latency', JSON.stringify(averageLatencyArray))
    return averageLatencyArray
}

Обработчик загрузки:

const getSasToken = async (container: string, account: string, ipAddress: string, fileType: string) => {
    const tokenResponse = await ax.post(
        `storage/sas`,
        {
            container,
            account,
            ipAddress,
            fileType,
        },
        {
            headers: {
                ...authHeader(),
            },
        },
    );
    if (tokenResponse.status !== 201 || !tokenResponse.data?.data?.sasToken) {
        console.error("Failed to get SAS token from backend!");
        return null;
    }

    const tokensResponseData = tokenResponse.data.data;
    const { sasToken } = tokensResponseData
    return sasToken
}
const handleUpload = async (container: string, account: string, ipAddress: string, file: File) => {
    const token = await getSasToken(container, account, ipAddress, file.type)
    if (!token) return null
    const blobService = new BlobService();
    return await blobService.uploadFile(file, token, container, account);
}
export const handleVideoUpload = async (file: File, container: string) => {
    try {

        let retryCounts = 0
        const ipAddress = "192.something";
        // await ax
        //  .get("http://api.ipify.org/?format=json")
        //  .then((response) => response.data)
        //  .then((data) => {
        //      if (data) {
        //          ipAddress = data.ip;
        //      }
        //  });
        if (file) {
            let leastLatencyAccounts = JSON.parse(localStorage.getItem('latency') || '[]')
            if (leastLatencyAccounts && leastLatencyAccounts?.length > 0) {
                const len = leastLatencyAccounts.length
                for (const accountInfo of leastLatencyAccounts) {
                    if (len >= 5 && retryCounts === 3 || len <= 4 && retryCounts === 2 || len === retryCounts) {
                        console.error("Failed to upload file with retries")
                        return null
                    }
                    const response = await handleUpload(container, accountInfo.account, ipAddress, file)
                    if (!response) {
                        console.error(`Failed to upload the file with account storage ${accountInfo.account}!`);
                        leastLatencyAccounts.shift()
                        localStorage.setItem('latency', JSON.stringify(leastLatencyAccounts))
                        retryCounts++;
                        continue;
                    }
                    return response;
                }
                // todo buy to set ip address, also encryption------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

            } else {
                const response = await handleUpload(container, azurePingContainers[ 0 ].account, ipAddress, file)
                if (!response) {
                    console.error(`Failed to upload the file with account storage ${azurePingContainers[ 0 ].account}!`);
                }
                return response;
            }
        }
    } catch (error) {
        console.error("There was an error uploading the file!", error);
    }
};

Служба загрузки:

export class BlobService {
    constructor() { }

    async uploadFile(file: File, token: string, container: string, account: string) {
        const fileName = this.generateFileName(file);
        try {
            const response = await this.uploadToBlobStorage(file, token, account, container, fileName);
            return { response, fileName };
        } catch (e) {
            console.error('Error processing token:', e);
            return null
        }

    }

    generateFileName(file: File): string {
        return `${file.name}-${Date.now()}.${file.name.split('.').pop()}`;
    }

    async uploadToBlobStorage(file: File, token: string, account: string, container: string, fileName: string): Promise<{ responseBlob: BlobUploadCommonResponse, account: string } | null> {
        const blobServiceClient = new BlobServiceClient(`https://${account}.blob.core.windows.net?${token}`);
        const containerClient = blobServiceClient.getContainerClient(container);
        const blockBlobClient = containerClient.getBlockBlobClient(fileName);

        const responseBlob = await this.upload(file, blockBlobClient);
        if (responseBlob.errorCode) {
            console.warn('Error in responseBlob:', responseBlob.errorCode);
            return null;
        }

        return { responseBlob, account };
    }

    async upload(file: File, blockBlobClient: BlockBlobClient) {


        console.info('Starting upload...');


        const response = await blockBlobClient.uploadData(file, {
            blobHTTPHeaders: { blobContentType: file.type },
            concurrency: 20
        });
        store.dispatch(setProgressValue(100))
        return response
    }


}

Бэкэнд:

async generateSAS(createSasTokenDto: GenerateSasTokenDto) {
    try {

      const { container, fileType, ipAddress ,account} = createSasTokenDto
      const permissions = new ContainerSASPermissions()
      permissions.write = true
      const blobServiceClient= await this.getGenericServiceClient(account)
      const blobContainerClient = await this.getGenericContainerClient(container, blobServiceClient)
      const zeroedSeconds = new Date().setSeconds(0)
      const options = {
        expiresOn: new Date(Date.now() + (1000 * 60 * 60 * 24 * 120 //?When to expire
        )),
        contentType: fileType,
        permissions,
        startsOn: new Date(zeroedSeconds),
        protocol: SASProtocol.Https,
        // ipRange: {
        //   start: ipAddress,
        //   end: ipAddress,
        // }
      }
      const sasToken = await blobContainerClient.generateSasUrl(options)
      return {
        sasToken:sasToken.split(`${container}?`)[1],
      }
    } catch (error) {
      console.error(error)
      throw new Error(error.message || "Failed to create to SAS")
    }
  }
 async getGenericServiceClient(account:string) {
    let accountKey=null;
    switch (account) {
      case AZURE_STORAGE_ACCOUNTS.US_EAST_2:
        accountKey = this.configService.getOrThrow('azure-connection-storage-eastus2-key')
        break;
      case AZURE_STORAGE_ACCOUNTS.UAE_NORTH:
        accountKey = this.configService.getOrThrow('azure-connection-storage-uaenorth-key')
        break;
        default:
          throw new Error('Invalid Azure Storage Account')
    }

    const url = `https://${account}.blob.core.windows.net`
    console.info(account,accountKey)
    return new BlobServiceClient(url,new StorageSharedKeyCredential(account,accountKey))
  }
  async getGenericContainerClient(container: string, blobServiceClient: BlobServiceClient) {

    return blobServiceClient.getContainerClient(container)
  }

Ожидание: Загрузите файл в лучший и ближайший к конечному пользователю источник. Результат: Front Door ВСЕГДА загружает файл в ПОСЛЕДНЮЮ добавленную учетную запись хранения или в последнюю. Настройки задержки

Можете ли вы поделиться своим полным кодом в вопросе?

Dasari Kamali 15.07.2024 14:45

@DasariKamali, во-первых, моя проблема не была решена, вместо этого я вручную рассчитал задержки при входе пользователя в систему, полностью отказавшись от входной двери. Мы могли бы подумать об использовании его для доставки, но на данный момент мы не доставляем файлы. Однако я обновлю вопрос с полным кодом.

Sufian Majid 15.07.2024 16:20
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
2
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мы можем использовать для этой цели входную дверь, мои зонды не сработали. Но такой подход устраняет необходимость в этом, если необходима только загрузка. Позже я смешал это с базой данных, сохранив учетные записи в базе данных в этом формате.

{
account:string,
url:string,
envVar:string
}

Таким образом, делая все динамичным.

Другие вопросы по теме