2016-09-14 6 views
0

Ich habe einen Express-Server, der als eine API ausgeführt wird, und ich habe eine Middleware als solche geladen:Express: run-Middleware einmal pro Sekunde

app.js

const lastActivity = require('./middleware/lastActivity'); 
app.use(lastActivity);` 

Middleware/lastActivity.js

module.exports = function(req, res, next) { 
    if (req.user && isDifferentDay(req.user.last_activity) { 
     User.findById(req.user.id, (err, user) => { 
      user.last_activity = Date.now(); 
      user.save((err) => { 
       // also do another async call to an external service, then 
       return next(); 
      } 
     }); 
    } 
}); 

So prüft sie, ob die last_activity Datum auf dem Benutzer gespeichert ist eine andere Tag als heute, und wenn ja, aktualisiert der Benutzer (ich interessiere mich nur für das Datum, nicht den bestimmten Zeitstempel). Es führt auch einen API-Aufruf an einen externen Dienst aus, um E-Mail-Marketingkampagnen zu verwalten.

Das Problem ist jedoch, dass meine Web-App zwei Ressourcen beim Laden der Seite zur gleichen Zeit anfordert. Das bedeutet, dass die isDifferentDay für beide zurückgegeben wird, und das Benutzermodell zweimal aktualisiert wird, und noch wichtiger, ich mache zwei API-Aufrufe an den externen Dienst, der ratenbegrenzt ist.

Eine naheliegende Lösung besteht darin, nur eine Anfrage gleichzeitig auf meinem Client zu stellen, aber ich möchte mich nicht darauf beschränken. Was ich will ist eine Art Express-Sperre, die nur die Middleware einmal pro Sekunde laufen lässt? Oder eine andere Lösung, die ich nicht sehen kann.

Was ist der beste Weg, dies in einer Express/Node-Art zu handhaben?

Vielen Dank.

+0

Sie Spezifikation von 'isDifferentDay' könnte falsch sein: zwei aufeinanderfolgende Anrufe, um es auf der gleichen Seite und am selben Tag sollen nicht beide true zurück (es sei denn, der erste Anruf um 23:59:59 und die nächsten empfangen wird um 0:00:00) – Flint

+0

wo speichern Sie die aktualisierte 'last_activity' in der Sitzung? Ich denke, wenn Sie die Sitzung ("req.user.last_activity") direkt nach der "if" Bedingung aktualisieren, wird es in Ordnung sein. Eine andere Sache - benutze 'findByIdAndUpdate' anstelle von findById und speichere. viel sauberer und schneller. – TomG

+0

'isDifferentDay' wird korrekt zurückgegeben, da beide Anfragen gleichzeitig ausgeführt werden. Wenn diese Funktion ausgeführt wird, wird für beide der Wert true zurückgegeben und der Pfad wird fortgesetzt. –

Antwort

1

Dieses Problem ist eine typische Wettlaufsituation.
Da Sie nur last_activity des Benutzers einmal pro Tag interessieren, anstelle findById zu verwenden, können Sie einen zusätzlichen Filter zur DB Anfrage hinzufügen UND sie in einem Zug aktualisieren. Zum Beispiel

var query = { 
    _id: req.user.id, 
    last_activity: req.user.last_activity 
}; 
User.findOneAndUpdate(query, { last_activity: Date.now() }, (err, user) => { 
    if (!user) 
     return; // user was changed between requests, do nothing 
    // ... the rest of your code 
}); 

Auf diese Weise werden Sie nur den Benutzer aktualisieren, wenn es last_activity zwischen Aktionen unverändert gelassen wurde wird.

Verwandte Themen