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 { 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;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue