Dans mon serveur d’parsing, j’ai une classe appelée Stats
qui contient les colonnes secondsPlayed
(number) et timeScore
(number)
J’utilise le code en nuage pour mettre à jour toutes les lignes de la colonne timeScore
Le code ci-dessous ne fonctionne que lors de la mise à jour et de l’enregistrement de 1 ou 2 objects results.length
. Si Parse.Query retourne plus de 2 résultats, le code se bloque et j’obtiens l’erreur suivante.
error: Failed running cloud function timeScore for user undefined with: Input: {} Error: {"code":101,"message":"Object not found."} functionName=timeScore, code=101, message=Object not found., , user=undefined error: Error generating response. ParseError { code: 101, message: 'Object not found.' } code=101, message=Object not found. error: Object not found. code=101, message=Object not found.
C’est un problème car j’ai besoin de mettre à jour et de sauvegarder des milliers d’objects. Quel est le meilleur moyen et le plus rapide de le faire?
Pourquoi mon code fonctionne-t-il pour 2 objects mais pas pour plus de 2? Comment puis-je réparer cela?
Voici mon code
var _ = require("underscore"); Parse.Cloud.define("timeScore", function(request, response) { var query = new Parse.Query("Stats"); query.greaterThan("secondsPlayed", 1000); query.find().then(function(results) { _.each(results, function(result) { var secondsPlayed = result.get("secondsPlayed") || 0; result.set("timeScore", secondsPlayed*2); }); return Parse.Object.saveAll(results); }).then(function(results) { response.success(results); }, function(error) { response.error(error); }); });
Voici comment je l’appelle
#!/usr/bin/env node var Parse = require("parse/node"); Parse.initialize("xx", "xx"); Parse.serverURL = "http://randomapp.herokuapp.com/parse"; Parse.Cloud.run('timeScore');
METTRE À JOUR:
Ci-dessous, mon dernier code. Tout fonctionne bien sauf le fait que j’obtiens l’erreur suivante sans raison apparente.
heroku[router]: at=error code=H12 desc="Request timeout" method=POST path="/parse/functions/timeScore
Je reçois l’erreur de dépassement de délai indépendamment de la taille de lot que je choisis et je l’obtiens toutes les 30 secondes. Je le reçois un total de 5 fois. Après la 5ème fois je ne l’obtiens plus. Je reçois la cinquième et dernière erreur au bout de 2,5 minutes environ (30 secondes * 5). Cette erreur n’a aucune incidence sur le processus. Tous les objects 250k sont mis à jour et enregistrés indépendamment de batchSize.
Je pensais que peut-être parce que je results.error
jamais results.error
ou results.success
le serveur pensait que je travaillais toujours et montrait l’erreur. Cependant, j’ai mis à jour mon code comme suit et j’obtiens toujours les erreurs de dépassement de délai.
De plus, après chaque erreur de temporisation, processBatch () est appelée à nouveau depuis le début. Depuis que j’ai 5 erreurs de timeout, processBatch () est appelé 5 fois. Donc, après la 5ème erreur de timeout, 5 fonctions processBatch () s’exécutant simultanément (je l’ai confirmé avec les journaux).
Quelle est la cause des erreurs de timeout heroku que je reçois? Comment je le répare?
var _ = require("underscore"); Parse.Cloud.define("timeScore", function(request, response) { var counter = 0; function processBatch(query, batchSize, startingAt, process) { query.limit(batchSize); query.skip(startingAt); return query.find().then(results => { return process(results).then(() => results.length); }).then(length => { return (length === batchSize)? processBatch(query, batchSize, startingAt+length, process) : {}; }); } function setTimeScores(stats) { console.log("LENGTH " + stats.length); _.each(stats, stat => { counter ++; stat.set("timeScore", counter); }); return Parse.Object.saveAll(stats); } var query = new Parse.Query("Stats"); processBatch(query, 2500, 0, setTimeScores).then(results => { response.success(results); }).catch(error => { response.error(error); }); });
Pour gérer un nombre d’objects supérieur à la limite de requête maximale, créez une fonction plus abstraite qui utilise limit()
de requête et skip()
pour faire défiler les données:
function processBatch(query, batchSize, startingAt, process) { query.limit(batchSize); query.skip(startingAt); return query.find().then(results => { return process(results).then(() => results.length); }).then(length => { return (length === batchSize)? processBatch(query, batchSize, startingAt+length, process) : {}; }); }
Ceci dit, obtenez un lot d’objects long, défini par query
, puis faites quelque chose avec les objects récupérés, puis, s’il y en a plus, refait la même chose, en ignorant les objects déjà traités.
Votre étape de processus ressemble à ceci:
function setTimeScores(stats) { _.each(stats, stat => { var secondsPlayed = stat.get("secondsPlayed") || 0; stat.set("timeScore", secondsPlayed*2); }); return Parse.Object.saveAll(stats); }
Appelez ça comme ça:
let query = new Parse.Query("Stats"); query.greaterThan("secondsPlayed", 1000); processBatch(query, 100, 0, setTimeScores);
EDIT dans le contexte d’une fonction cloud, appelez-le comme ça …
Parse.Cloud.define("computeStats", function(request, response) { let query = new Parse.Query("Stats"); query.greaterThan("secondsPlayed", 1000); processBatch(query, 100, 0, setTimeScores).then(results => { response.success(results); }).catch(error => { response.error(error); }); });