Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Paralelizando promesas

Paralelizando promesas

LimaJS 20/06/2018

Lupo Montero

June 20, 2018
Tweet

More Decks by Lupo Montero

Other Decks in Programming

Transcript

  1. { Error: An internal error has occurred. Raw server response:

    "{"error":{"code":400,"message":"QUOTA_EXCEEDED : Exceeded quota for deleting accounts.","errors":[{"message":"QUOTA_EXCEEDED : Exceeded quota for deleting accounts.","domain":"global","reason":"invalid"}]}}" at FirebaseAuthError.FirebaseError [as constructor] (/Users/lupo/work/lupomontero/paralelizando-promesas/node_modules/firebase-admin/lib/utils/error.js:39:28) at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/Users/lupo/work/lupomontero/paralelizando-promesas/node_modules/firebase-admin/lib/utils/error.js:85:28) at new FirebaseAuthError (/Users/lupo/work/lupomontero/paralelizando-promesas/node_modules/firebase-admin/lib/utils/error.js:143:16) at Function.FirebaseAuthError.fromServerError (/Users/lupo/work/lupomontero/paralelizando-promesas/node_modules/firebase-admin/lib/utils/error.js:173:16) at /Users/lupo/work/lupomontero/paralelizando-promesas/node_modules/firebase-admin/lib/auth/auth-api-request.js:723 :45 at process._tickCallback (internal/process/next_tick.js:68:7) errorInfo: { code: 'auth/internal-error', message: 'An internal error has occurred. Raw server response: "{"error":{"code":400,"message":"QUOTA_EXCEEDED : Exceeded quota for deleting accounts.","errors":[{"message":"QUOTA_EXCEEDED : Exceeded quota for deleting accounts.","domain":"global","reason":"invalid"}]}}"' }, codePrefix: 'auth' } QUOTA_EXCEEDED : Exceeded quota for deleting accounts.
  2. Requerimientos • No más de 10 tareas (invocaciones a auth.deleteUser())

    por segundo. • Batches (grupos) de 10 • Intervalo entre batches (1 seg) • Si una tarea falla las demás deben continuar
  3. Tareas vs promesas const promises = users.map(user => auth.deleteUser(user.localId)) const

    tasks = users.map(user => () => auth.deleteUser(user.localId))
  4. Series const series = (tasks, results = []) => (

    (!tasks.length) ? Promise.resolve(results) : tasks[0]().then(result => series(tasks.slice(1), [...results, result])) );
  5. Dividiendo arreglo en “batches” (grupos?) const splitArrayIntoBatches = (arr, limit)

    => arr.reduce((memo, item) => { if (memo.length && memo[memo.length - 1].length < limit) { memo[memo. length - 1].push(item); return memo; } return [...memo, [item]] ; }, []);
  6. const array = ['a', 'b', 'c', 'd', 'e']; splitArrayIntoBatches(array, 1);

    // => [['a'], ['b'], ['c'], ['d'], ['e']] splitArrayIntoBatches(array, 2); // => [['a', 'b'], ['c', 'd'], ['e']] splitArrayIntoBatches(array, 3); // => [['a', 'b', 'c'], ['d', 'e']] splitArrayIntoBatches(array, 4); // => [['a', 'b', 'c', 'd'], ['e']] splitArrayIntoBatches(array, 5); // => [['a', 'b', 'c', 'd', 'e']]
  7. const batched = (tasks, concurrency) => { const processBatches =

    (batches, prevResults = []) => { if (!batches.length) { return Promise.resolve(prevResults) ; } return Promise.all(batches[0].map(fn => fn())).then((batchResults) => { const results = [...prevResults, ...batchResults] ; return (batches.length <= 1) ? results : processBatches(batches. slice(1), results); }); }; return processBatches(splitArrayIntoBatches(tasks, concurrency)) ; };
  8. // ejecuta todas las tareas de 5 en 5 batched(tasks,

    5) .then(console.log) .catch(console.error);
  9. Agregando tiempo de espera entre lotes // Antes processBatches(batches. slice(1),

    results).then(resolve, reject) // Después new Promise((resolve, reject) => setTimeout( () => processBatches(batches. slice(1), results) .then(resolve, reject), interval, ))
  10. const throttled = (tasks, concurrency, interval = 0) => {

    const processBatches = (batches, prevResults = []) => { if (!batches.length) { return Promise.resolve(prevResults) ; } return Promise.all(batches[0].map(fn => fn())).then((batchResults) => { const results = [...prevResults, ...batchResults] ; return (batches.length <= 1) ? results : new Promise((resolve, reject) => setTimeout( () => processBatches(batches. slice(1), results).then(resolve, reject), interval, )); }); }; return processBatches(splitArrayIntoBatches(tasks, concurrency)) ; };
  11. // ejecuta tareas de 5 en 5, // esperando 1s

    entre cada lote throttled(tasks, 5, 1000) .then(console.log) .catch(console.error);
  12. // así procesábamos las tareas de un batch (en parallelo)

    Promise.all( batches[0].map(fn => fn()), ) // agregamos la opción `failFast` y manejejamos errores cuando // `failFast` sea `false` Promise.all( batches[0].map(fn => (failFast ? fn() : fn(). catch(err => err))), )
  13. const pact = (tasks, concurrency, interval = 0, failFast =

    true) => { const processBatches = (batches, prevResults = []) => { if (!batches.length) { return Promise.resolve(prevResults) ; } return Promise.all( batches[ 0].map(fn => (failFast ? fn() : fn(). catch(err => err))), ).then((batchResults) => { const results = [...prevResults, ...batchResults] ; return (batches.length <= 1) ? results : new Promise((resolve, reject) => setTimeout( () => processBatches(batches. slice(1), results).then(resolve, reject), interval, )); }); }; return processBatches(splitArrayIntoBatches(tasks, concurrency)) ; };