Parallel products feed data fetching (#465)

* Parallel products feed data fetching

* Create strong-peas-begin.md
This commit is contained in:
Krzysztof Wolski 2023-05-17 13:26:36 +02:00 committed by GitHub
parent 51134a5a8b
commit 2de2a40af1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 32 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-app-products-feed": patch
---
Query for the product details run now in paralell to speed up overall feed generation

View file

@ -0,0 +1,9 @@
query FetchProductCursors($first:Int!, $after: String, $channel: String!){
productVariants(first:$first, after: $after, channel: $channel){
pageInfo{
hasNextPage
startCursor
endCursor
}
}
}

View file

@ -2,10 +2,64 @@ import { url } from "inspector";
import { Client } from "urql"; import { Client } from "urql";
import { createLogger } from "@saleor/apps-shared"; import { createLogger } from "@saleor/apps-shared";
import { import {
FetchProductCursorsDocument,
FetchProductDataForFeedDocument, FetchProductDataForFeedDocument,
GoogleFeedProductVariantFragment, GoogleFeedProductVariantFragment,
} from "../../../generated/graphql"; } from "../../../generated/graphql";
const getCursors = async ({ client, channel }: { client: Client; channel: string }) => {
let result = await client
.query(FetchProductCursorsDocument, { channel: channel as string, first: 100 })
.toPromise();
// First page is queried without the `after` param, so we start an array with `undefined`
const cursors: Array<string | undefined> = [undefined];
while (result.data?.productVariants?.pageInfo.hasNextPage) {
result = await client
.query(FetchProductCursorsDocument, {
channel: channel as string,
first: 100,
after: result.data.productVariants.pageInfo.endCursor,
})
.toPromise();
const endCursor = result.data?.productVariants?.pageInfo.endCursor;
if (endCursor) {
cursors.push(endCursor);
}
}
return cursors;
};
const fetchVariants = async ({
client,
after,
channel,
}: {
client: Client;
after?: string;
channel: string;
}): Promise<GoogleFeedProductVariantFragment[]> => {
const logger = createLogger({ saleorApiUrl: url, channel, fn: "fetchVariants" });
const result = await client
.query(FetchProductDataForFeedDocument, {
channel: channel as string,
first: 100,
after,
})
.toPromise();
if (result.error) {
logger.error(`Error during the GraphqlAPI call: ${result.error.message}`);
return [];
}
return result.data?.productVariants?.edges.map((e) => e.node) || [];
};
interface FetchProductDataArgs { interface FetchProductDataArgs {
client: Client; client: Client;
channel: string; channel: string;
@ -14,40 +68,13 @@ interface FetchProductDataArgs {
export const fetchProductData = async ({ client, channel }: FetchProductDataArgs) => { export const fetchProductData = async ({ client, channel }: FetchProductDataArgs) => {
const logger = createLogger({ saleorApiUrl: url, channel, route: "Google Product Feed" }); const logger = createLogger({ saleorApiUrl: url, channel, route: "Google Product Feed" });
let result = await client const cursors = await getCursors({ client, channel });
.query(FetchProductDataForFeedDocument, { channel: channel as string, first: 100 })
.toPromise();
if (result.error) { logger.debug(`Query generated ${cursors.length} cursors`);
logger.error(`Error during the GraphqlAPI call: ${result.error.message}`);
throw new Error("Error during the GraphQL API call");
}
let variants: GoogleFeedProductVariantFragment[] = const promises = cursors.map((cursor) => fetchVariants({ client, after: cursor, channel }));
result.data?.productVariants?.edges.map((e) => e.node) || [];
while (result.data?.productVariants?.pageInfo.hasNextPage) { const results = await Promise.all(promises);
logger.debug("Fetching the next page of products");
result = await client return results.flat();
.query(FetchProductDataForFeedDocument, {
channel: channel as string,
first: 100,
after: result.data.productVariants.pageInfo.endCursor,
})
.toPromise();
if (result.error) {
logger.error(`Error during the GraphqlAPI call: ${result.error.message}`);
throw new Error("Error during the GraphQL API call");
}
if (!result.data?.productVariants?.edges.length) {
logger.warn("Fetching the second page of results resulted in no entries");
break;
}
variants = variants?.concat(result.data?.productVariants?.edges.map((e) => e.node));
}
return variants;
}; };