Ashish
Ashish

Reputation: 31

Issue with useMutation with await and promise

I am performing the useMutation operation in the innermost loop and want to check the remaining cost upon every mutation. But it gets checked after all the mutations which is a problem because for some reason even if all the mutations get done(When the cost is under limits), It calls the .then() part for cost-checking and waiting for unknown reason.

Edit: I also noticed that even though the program is waiting again and again, the network status of chrome shows that all the mutations have happened and only the query of handleDiscountMore i.e. fetchMore is pending

const { loading, error, data, fetchMore, extensions, refetch } = useQuery(GET_COLLECTION, {
    variables: { "id": coll.collection.id }
  });

const [updatePrice] = useMutation(UPDATE_PRICE);

const redirectToModify = async (data, totalProducts) => {
    wait(20000);
    var cursor, fetchCount;
    fetchCount = data.collection.products.edges.length;
    totalProducts -= fetchCount;

    data.collection.products.edges.map(async(product) => {
      const results = await Promise.all(product.node.variants.edges.map(variant => {
        if (selected == 'curr_price') {
          //do stuff
        }
        else {
          //do stuff
        }
        const productVariableInput = {
          //Object
        };

        updatePrice({ variables: { input: productVariableInput } }).then(({ data, extensions }) => {
          console.log("Remaining", extensions.cost.throttleStatus.currentlyAvailable) 
          console.log(data)
          if (extensions.cost.throttleStatus.currentlyAvailable < 100) {
            console.log("WAITING")
            wait(18000);
          }
        }).catch(e => {
          console.log(e)
        })
        console.log("AFTER")
        return 0;
      }))
    })
        
    if (totalProducts > 0) {
      console.log("Calling")
      wait(15000);
      handleDiscountMore(data, cursor, totalProducts)  
    }
  };

//Below function is Just for reference. It gets called before checking the throttleStatus above. afaik there's no problem with this

const handleDiscountMore = (data, cursor, pc) => { 
    console.log("Call received")
    fetchMore({
      variables: {
        "id": data.collection.id,
        "cursor": cursor
      },
      updateQuery: (
        previousResult,
        { fetchMoreResult }
      ) => {
        console.log("adding", fetchMoreResult);
        redirectToModify(fetchMoreResult, pc);
        // return fetchMoreResult;
      }
    })
  }

Upvotes: 1

Views: 7003

Answers (1)

Amoliski
Amoliski

Reputation: 159

Your map of maps is evaluating all promises at exactly the same time. Here's a cleaned up example that uses a nested for loop instead, which will wait for each request to finish before starting the next (note: I couldn't run it to test, so there's probably some bugs, but the idea is there):

const id = coll.collection.id;
const { loading, error, data, fetchMore, extensions, refetch } = useQuery(GET_COLLECTION, {
    variables: { id }
});

const [updatePrice] = useMutation(UPDATE_PRICE);

// Given a product, returns a promise that resolves when all variants are processed
async function process_product(product){
    const variants = product.node.variants.edges;
    for (let i = 0; i < variants.length; i++){
        await process_variant(variants[i]);
    }
}

// Given a variant, returns a promise after the product is processed
async function process_variant(variant){
    if (variant) {
        console.log('doing stuff')
    }
    else {
        console.log('doing other stuff')
    }
    const productVariableInput = {};
    const variables = { input: productVariableInput };

    try {
        const {data, extensions} = await updatePrice({ variables });
        const remaining_throttle = extensions.cost.throttleStatus.currentlyAvailable;
        console.log("Remaining", remaining_throttle)
        console.log(data)

        // Change to a while loop to make sure you actually wait until resources are available
        if (remaining_throttle < 100) {
            console.log("WAITING")
            await wait(18000);
        }
    } catch (e) {
        console.log('error:', e);
    }
    console.log("AFTER")
    return 0;
}

const redirectToModify = async (data, totalProducts) => {
    await wait(20000);
    let cursor;
    const products = data.collection.product.edges;

    totalProducts = totalProducts - products.length;

    // Wait for all products to finish processing
    for (var i = 0; i < products.length; i++){
        await process_product(products[i]);
    }

    if (totalProducts > 0) {
        console.log("Calling")
        await wait(15000);
        handleDiscountMore(data, cursor, totalProducts)
    }
};

function updateQuery(previousResult, { fetchMoreResult }){
    console.log("adding", fetchMoreResult);
    redirectToModify(fetchMoreResult, pc);
    return fetchMoreResult;
}
//Below function is Just for reference. It gets called before checking the throttleStatus above. afaik there's no problem with this
function handleDiscountMore(data, cursor, pc) {
    console.log("Call received")
    const variables = { id: data.collection.id, cursor };
    fetchMore({ variables, updateQuery })
}

Upvotes: 3

Related Questions