node.jsfirebasegoogle-cloud-firestoreironsource

I'm getting duplicate results because nodejs judges it as a send failure before even sending a 200 response


When the app participates in a reward event, the reward server sends the result to the app server. If there is no 200 response, the reward company server repeatedly sends the result for a certain period of time.

If the app server does not respond with 200, the reward server repeatedly sends the result.

All points earned are recorded. Check if there is a point record with the event ID, and if there is no point record, record the points and respond with 200. The problem is that even before the first 200 response, it is judged as a transmission failure, and the result is sent again, so multiple points with the same event ID are accumulating.

What should I do? Is there a way to handle this on the app server?

db.collection('pointHistory').doc(uid).collection('pointHistory').add(newPointHistory).then(ref => {
                    db.collection('users').doc(uid).update({point: addTotalPoint});
                    db.collection('offerwallHistory').doc(uid).collection('offerwallHistory').add(offerwallHistory_data);
                    db.collection('adminPointHistory').add(adminPointHistory_data);
                    setDailyPointStatus(reward, 12);
                    setOtherPersonalPointStatus(reward, uid, "dailyPersonalPointStatus");
                    setOtherPersonalPointStatus(reward, uid, "weeklyPersonalPointStatus");
                    setOtherPersonalPointStatus(reward, uid, "monthlyPersonalPointStatus");
                    return res.send(event_id + ":OK").status(200);
                }).catch(err => {
                    console.log(err);
                    return null;
                });
                return res.send(event_id + ":OK").status(200);

Solution

  • Yes, your doing it wrong. Your using promise(then/catch) that not wait for the all process to be done. You should try and learn more about async / await to make your code cleaner and readble and you can use it like you just did but without the return return res.send(event_id + ":OK").status(200); at the end. for example:

    try {
      await db.collection('pointHistory').doc(uid).collection('pointHistory').add(newPointHistory)
      await db.collection('users').doc(uid).update({point: addTotalPoint});
      db.collection('offerwallHistory').doc(uid).collection('offerwallHistory').add(offerwallHistory_data);
      db.collection('adminPointHistory').add(adminPointHistory_data);
      setDailyPointStatus(reward, 12);
      setOtherPersonalPointStatus(reward, uid, "dailyPersonalPointStatus");
      setOtherPersonalPointStatus(reward, uid, "weeklyPersonalPointStatus");
      setOtherPersonalPointStatus(reward, uid, "monthlyPersonalPointStatus");
      return res.send(event_id + ":OK").status(200);
    } catch(error) {
      return null; 
    }

    You need to wrap the function like this:

    async function myFunc() {}