Parallel products feed data fetching (#465)
* Parallel products feed data fetching * Create strong-peas-begin.md
This commit is contained in:
parent
51134a5a8b
commit
2de2a40af1
3 changed files with 73 additions and 32 deletions
5
.changeset/strong-peas-begin.md
Normal file
5
.changeset/strong-peas-begin.md
Normal 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
|
|
@ -0,0 +1,9 @@
|
|||
query FetchProductCursors($first:Int!, $after: String, $channel: String!){
|
||||
productVariants(first:$first, after: $after, channel: $channel){
|
||||
pageInfo{
|
||||
hasNextPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,10 +2,64 @@ import { url } from "inspector";
|
|||
import { Client } from "urql";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import {
|
||||
FetchProductCursorsDocument,
|
||||
FetchProductDataForFeedDocument,
|
||||
GoogleFeedProductVariantFragment,
|
||||
} 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 {
|
||||
client: Client;
|
||||
channel: string;
|
||||
|
@ -14,40 +68,13 @@ interface FetchProductDataArgs {
|
|||
export const fetchProductData = async ({ client, channel }: FetchProductDataArgs) => {
|
||||
const logger = createLogger({ saleorApiUrl: url, channel, route: "Google Product Feed" });
|
||||
|
||||
let result = await client
|
||||
.query(FetchProductDataForFeedDocument, { channel: channel as string, first: 100 })
|
||||
.toPromise();
|
||||
const cursors = await getCursors({ client, channel });
|
||||
|
||||
if (result.error) {
|
||||
logger.error(`Error during the GraphqlAPI call: ${result.error.message}`);
|
||||
throw new Error("Error during the GraphQL API call");
|
||||
}
|
||||
logger.debug(`Query generated ${cursors.length} cursors`);
|
||||
|
||||
let variants: GoogleFeedProductVariantFragment[] =
|
||||
result.data?.productVariants?.edges.map((e) => e.node) || [];
|
||||
const promises = cursors.map((cursor) => fetchVariants({ client, after: cursor, channel }));
|
||||
|
||||
while (result.data?.productVariants?.pageInfo.hasNextPage) {
|
||||
logger.debug("Fetching the next page of products");
|
||||
const results = await Promise.all(promises);
|
||||
|
||||
result = await client
|
||||
.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;
|
||||
return results.flat();
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue