簡體   English   中英

在將對象的錯誤數組推送到 CSV 之前等待 promise 完成

[英]Wait for promises to complete before pushing error array of objects to CSV

我正在嘗試從 Okta 導入和刪除大量用戶,同時保持在速率限制內,並將任何錯誤記錄到 excel。 下面的代碼似乎可以工作,但只是我在控制台日志上看到的 5 個錯誤中的最后一個沒有出現在輸出的 CSV 中。

我嘗試了一系列替代方法,包括將 csvWriter 調用放入 a.then 而不是 the.finally。 問題是它沒有等待最后一個錯誤被推送到數組。

 "use strict"; const okta = require("@okta/okta-sdk-nodejs"); const csv = require("csv-parser"); const fs = require("fs"); const createCsvWriter = require("csv-writer").createObjectCsvWriter; let timeRun = new Date().toISOString().replace(/T/, " ") // replace T with a space.replace(/\..+/, "") // delete the dot and everything after.replace(/:/g, "."); // replace T with a space const csvWriter = createCsvWriter({ path: "errorLog-" + timeRun + ".csv", header: [ { id: "error", title: "Error" }, { id: "row", title: "Row" }, ], }); let record = []; let currentError = {} // Enter tenant info and API key here const client = new okta.Client({ orgUrl: "https://xxxxxxxx.oktapreview.com", token: "xxxxxxxxxxxxxxxxxxxxxxx", }); let usersToDelete = []; let currentUserID; var getUsersToDelete = new Promise((resolve, reject) => { fs.createReadStream("testImport.csv").pipe(csv()).on("data", (row) => { usersToDelete.push(row); }).on("end", (row) => { resolve(); }); }); getUsersToDelete.then(async () => { let iCount = 1; while (usersToDelete.length > 0) { var deleteUserTimeout = new Promise((resolve, reject) => { setTimeout(async function () { currentUserID = usersToDelete.pop(); client.getUser(currentUserID.email).then(async (user) => { return user.deactivate().then(() => console.log("User has been deactivated")).then(() => user.delete()).then(() => console.log("User has been deleted")); }).catch(async function (error, row) { currentError = { error: error.message, row: "row" }; console.error(currentError); return error; }).finally(() => { record.push(currentError); reject() }); resolve(); }, 2000); }); await deleteUserTimeout; console.log("Timeout" + currentUserID, "Iteration: " + iCount); iCount++ } }).finally(async () => { await csvWriter.writeRecords(record); });

在您的deleteUserTimeout promise 中有一場比賽。 它在client.getUser之后立即解決而不等待結果。

var deleteUserTimeout = new Promise((resolve, reject) => {
  setTimeout(async function () {
    currentUserID = usersToDelete.pop();
    client.getUser(currentUserID.email) // forgot to await this
    //... snip
    resolve(); // resolves immediately
  }, 2000);
});
await deleteUserTimeout; // this won't wait for the delete

為了清楚起見,我會對其進行重構(未經測試):

async function deleteUser(email) {
  let user = await client.getUser(email);
  await user.deactivate();
  await user.delete();
}

function sleep(timeoutMs) {
  return new Promise(_ => setTimeout(_, timeoutMs));
}

async function deleteUsers(usersToDelete) {
  const errors = [];

  for (let row = 0; row < usersToDelete.length; row++) {
    let currentUserID = usersToDelete[row];
    await sleep(2000);
    await deleteUser(currentUserID.email)
      .catch(error => {
        errors.push({error: error.message, row});
      });
  }

  return errors;
}

您的deleteUserTimeout promise 沒有等待用戶刪除操作完成,並且腳本在為最后一個要刪除的用戶啟動setTimeout回調后幾乎立即完成。 CSV 將寫入該時間累積的所有錯誤record ,而不是等待某些操作完成,包括遇到錯誤的 5 次迭代。

基本思想與@teppic 相同,但您可能希望在發現的每個錯誤時寫出,而不是將它們延遲到最后,以減少在腳本因任何原因崩潰時丟失錯誤信息的可能性(例如機器斷電)。

const sleep = time => new Promise(resolve => setTimeout(resolve, time))

const deleteUser = async email => {
  const user = await client.getUser(email)
  await user.deactivate()
  await user.delete()
}

const deleteUsers = async users => {
  for (const user of users) {
    try {
      await deleteUser(user.email)
      console.log(`Deleted ${user.email}`)
      await sleep(2000)
    } catch (e) {
      console.error(e.message)
      await csvWriter.writeRecords([{error: e.message, row: 'row'}])
    }
  }
}

getUsersToDelete.then(() => deleteUsers(usersToDelete))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM