2017-05-24 6 views
-1

J'ai une fonction qui:
1. obtient un tableau de 3000 propriétés 'id' à partir de documents mongoDB de la collection foo.
2. Crée une requête GET pour chaque ID afin d'obtenir l'obj 'resp' pour l'identifiant et le stocke dans une autre base de données.Erreur: se connecter ETIMEDOUT lors de raclage

router.get('/', (req, res) => { 

    var collection = db.get().collection('foo'); 
    var collection2 = db.get().collection('test'); 
    collection.distinct('id', (err, idArr) => { // count: 3000+ 
    idArr.forEach(id => { 
    let url = 'https://externalapi.io/id=' + id 
    request(url, (error, response, body) => { 
      if (error) { 
      console.log(error) 
      } else { 
      resp = JSON.parse(resp); 
      collection2.insert(resp); 
      } 
    }); 
}); 

Erreur nœud journal:

[0] events.js:163 
[0]  throw er; // Unhandled 'error' event 
[0]  ^
[0] 
[0] Error: connect ETIMEDOUT [EXT URL REDACTED] 
[0]  at Object.exports._errnoException (util.js:1050:11) 
[0]  at exports._exceptionWithHostPort (util.js:1073:20) 
[0]  at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1093:14) 

J'utilise limiteur taux simple pour ne pas causer des limites de taux (de 25cps):

const limit = require("simple-rate-limiter"); 
const request = limit(require("request")).to(20).per(1000); 

Mais quelque part entre 300-1700 demandes I recevez cette erreur qui bloque le noeud sur la ligne de commande. Comment puis-je gérer cette erreur pour empêcher mon application de se bloquer?

J'ai essayé beaucoup de la gestion des erreurs, mais aucun d'entre eux étaient en mesure de gérer connect ETIMEDOUT

+1

je vais vous relier à une réponse précédente de la mienne: https://stackoverflow.com/questions/29812692/node-js-server-timeout- problems-ec2-express-pm2/43806215 # 43806215 – arboreal84

+1

Combien de demandes exécutez-vous en même temps sur le même hôte? Je suppose que vous en exécutez trop, ce qui est soit un problème pour votre serveur ou pour l'hôte que vous essayez d'obtenir des données. – jfriend00

+0

J'essaie d'exécuter 10 demandes par seconde, pour 2750 IDs. Le point n'est pas de ralentir, car j'ai diviser et conquérir la méthode que j'intègre. J'essaye juste d'attraper l'erreur, et continue le programme, en enregistrant le 'id' à un failureArr ainsi je peux courir le manuscrit avec le arr. @ jfriend00 – Moshe

Répondre

2

Comme indiqué dans les commentaires, si vous voulez contrôler le nombre maximum de demandes qui sont en même temps en vol , vous pouvez utiliser Bluebird à faire assez facilement comme ceci:

const Promise = require('bluebird'); 
const rp = require('request-promise'); 

router.get('/', (req, res) => { 

    let collection = db.get().collection('foo'); 
    let collection2 = db.get().collection('test'); 
    collection.distinct('id', (err, idArr) => { // count: 3000+ 
     if (err) { 
      // handle error here, send some error response 
      res.status(501).send(...); 
     } else { 
      Promise.map(idArr, id => { 
       let url = 'https://externalapi.io/id=' + id 
       return rp(url).then(body => { 
        if (error) { 
         console.log(error) 
        } else { 
         let resp = JSON.parse(body); 
         // probably want to return a promise here too, but I'm unsure what DB you're using 
         collection2.insert(resp); 
        } 
       }).catch(err => { 
        // decide what you want to do when a single request fails here 
        // by providing a catch handler that does not rethrow, other requests will continue 
       }); 
        // pick some concurrency value here that does not cause errors 
      }, {concurrency: 10}).then(() => { 
       // all requests are done, send final response 
       res.send(...); 
      }).catch(err => { 
       // your code may never get here (depends upon earlier .catch() handler) 
      }); 
     } 
    }); 
}); 
+0

Voici un scénario: Un Admin dans le tableau de bord admin clique sur un bouton qui dit "Update DB", quand ce bouton est cliqué, cette route est déclenchée. Maintenant, je peux envoyer une réponse immédiatement "ok", alors que tout le travail est fait en arrière-plan ... comment puis-je obtenir une réponse de confirmation? c'est-à-dire "terminé" ou simplement envoyer une réponse au client une fois que tout est fait (attendre que cette réponse prenne plus de 10 minutes.) – Moshe

+0

'// probablement vouloir retourner une promesse ici aussi, mais je ne sais pas ce que vous DB ' re using' Moshe

+1

@Moshe - Les navigateurs n'aiment pas vraiment attendre 10 minutes pour une réponse HTTP. Il peut probablement être fait avec divers trucs aux deux extrémités. Une idée consiste à faire en sorte que le client connecte une connexion webSocket ou socket.io et que vous donniez une réponse HTTP immédiate, puis transmettiez la progression de la connexion webSocket/socket.io. – jfriend00