1
votes

Comment attendre dans une requête jusqu'à ce qu'une autre requête termine l'exécution de la même fonction dans nodeJS

J'utilise météore. J'ai un itinéraire défini dans le routeur de fer comme suit,

Router.route('/api/generatereceipt', {where: 'server'}).post(function(req, res, next) {
  console.log("API: generatereceipt invoked.");
  const reqBody = req.body;
  ....
}

Je veux générer un reçu un à la fois. c'est-à-dire que le reçu doit avoir un numéro unique qui est de nature incrémentielle.

En ce moment, je lis le numéro de reçu précédemment stocké et je l'incrémente de un. Je considère cela comme le numéro de reçu pour le traitement actuel du reçu.

Cependant, cela fonctionne bien tant que l'API generatereceipt n'est pas appelée simultanément par plusieurs clients. Lorsque l'API est appelée simultanément, le même numéro de reçu est considéré pour tous les reçus traités simultanément.

Par conséquent, je souhaite faire une demande de vérification si la même API REST est appelée par un autre client dans une autre demande est en cours. S'il est en cours, je souhaite attendre la fin de son exécution dans ce fil de requête.


0 commentaires

3 Réponses :


0
votes

Utilisez async et attendez la fin d'une requête.


1 commentaires

Mais async await ne fonctionne que dans le thread actuel. Comment voir si cette API s'exécute sur un autre thread? ou autre demande?



1
votes

Je suppose que cela utilise une sorte de base de données / backend pour stocker les identifiants de reçus? Si tel est le cas, vous devez utiliser des contraintes sur votre base de données pour vous assurer que l'ID de réception est unique. Mieux encore, pourquoi ne pas faire de la colonne d'identifiant de reçu une incrémentation automatique, alors vous n'avez pas besoin de vérifier le numéro de reçu précédent et de l'incrémenter vous-même, il sera géré par la couche de base de données et il sera simplement renvoyé dans le cadre de l'insertion. < / p>

S'il n'est pas nécessaire de procéder à une incrémentation automatique, envisagez simplement d'utiliser un UUID.

Je ne vois pas une seule raison pour laquelle vous voudriez attendre l'exécution. Cela ralentirait votre application pour toute personne autre que la première demande et ne serait pas évolutive.

Si vous avez vraiment une raison légitime de le structurer de cette façon et de générer vous-même l'auto-incrémentation, alors il serait préférable d'expliquer en détail pourquoi c'est le cas car il y a peut-être de meilleures solutions que de simplement "bloquer" le suivant


2 commentaires

Merci. Je pensais faire la même chose mais je me suis simplement demandé si nous pouvions vérifier l'exécution d'une autre demande. J'utiliserais $ inc pour mongo ou autoValue de SimpleSchema en en faisant un champ unique. Merci.


Heureux que ce soit trié, si cette réponse vous a aidé, n'hésitez pas à la marquer comme réponse acceptée



1
votes

Il ne devrait y avoir aucun problème avec les demandes simultanées. Voir l'exemple suivant:

=> Meteor server restarted                    
I20200703-09:59:15.911(2)? 9  =>  9
I20200703-09:59:15.912(2)? 7  =>  7
I20200703-09:59:15.913(2)? 4  =>  4
I20200703-09:59:15.913(2)? 0  =>  0
I20200703-09:59:15.913(2)? 21  =>  21
I20200703-09:59:15.913(2)? 24  =>  24
I20200703-09:59:15.913(2)? 17  =>  17
I20200703-09:59:15.913(2)? 18  =>  18
I20200703-09:59:15.915(2)? 2  =>  2
I20200703-09:59:15.917(2)? 19  =>  19
I20200703-09:59:15.923(2)? 6  =>  6
I20200703-09:59:15.923(2)? 23  =>  23
I20200703-09:59:15.925(2)? 11  =>  11
I20200703-09:59:15.928(2)? 8  =>  8
I20200703-09:59:15.931(2)? 16  =>  16
I20200703-09:59:15.932(2)? 10  =>  10
I20200703-09:59:15.934(2)? 5  =>  5
I20200703-09:59:15.934(2)? 13  =>  13
I20200703-09:59:15.934(2)? 22  =>  22
I20200703-09:59:15.936(2)? 20  =>  20
I20200703-09:59:15.936(2)? 15  =>  15
I20200703-09:59:15.939(2)? 14  =>  14
I20200703-09:59:15.940(2)? 1  =>  1
I20200703-09:59:15.940(2)? 3  =>  3
I20200703-09:59:15.943(2)? 12  =>  12

comme vous pouvez le voir, les appels se résoudront aux identifiants incrémentés:

import { Meteor } from 'meteor/meteor'
import { WebApp } from 'meteor/webapp'
import { HTTP } from 'meteor/http'

// create a simple HTTP route

WebApp.connectHandlers.use('/api/generatereceipt', function (req, res, next) {
   // random 0 - 50ms timeout to simulate response delay
  const randomTimeout = Math.floor(Math.random() * 50)

  // use Meteor's Promise.await to await async in non-async functions
  // --> should prevent troubles with legacy iron-router
  const receipt = Promise.await(getReceipt())
  
  setTimeout(() => {
    res.writeHead(200)
    res.end(String(receipt))
  }, randomTimeout)
})

// increment id and return new value
let receiptId = 0
async function getReceipt () {
  return receiptId++
}



Meteor.startup(function () {
  let testCount = 0
  const url = Meteor.absoluteUrl('/api/generatereceipt')

  // simulate concurrent calls by using a timeout of 0
  function call (id) {
    setTimeout(Meteor.bindEnvironment(() => {
      // simulate calling the /api/generatereceipt route
      const response = HTTP.get(url)
      console.log(id, ' => ', response.content) // should match
    }, 0))
  }

  for (let i = 0; i < 25; i++) {
    call(testCount++)
  }
})


3 commentaires

La solution que vous avez donnée ne fonctionne que lorsqu'un même client effectue des requêtes simultanées. Mon exigence était de connaître l'exécution de la méthode à partir de différentes requêtes. Pour le même client, je peux même utiliser this.unblock de Meteor pour une méthode qui permettra l'exécution simultanée de méthodes. Quoi qu'il en soit, merci d'avoir montré une manière différente de faire des demandes simultanées. Merci.


this.unblock ne fonctionne que dans les méthodes Meteor utilisant un client connecté DDP, tandis que les routes de routeur de fer sont basées sur HTTP et il n'y aurait pas de déblocage disponible. Il n'y a pas non plus de réelle concurrence, car le serveur de nœuds est toujours menacé et toutes les demandes entrantes sont toujours traitées dans un seul thread. J'ai plutôt l'impression que vous générez plusieurs processus et que vous rencontrez le problème que chaque processus a son propre compteur. Dans un tel cas, vous devrez compter sur une collection Mongo pour persister à contrer.


Ohh .. oui je n'ai jamais considéré que je suis dans un routeur de fer. unblock ne fonctionne que dans une méthode Meteor. Et comme vous le dites, nous devons nous appuyer sur une collection mongo pour conserver un compteur global qui peut être vu par n'importe quel processus à partir de n'importe quelle demande. Le package npm mongodb-autoincrement fait la même chose.