javascript - 在将对象的错误数组推送到 CSV 之前等待 promise 完成
问题描述
我正在尝试从 Okta 导入和删除大量用户,同时保持在速率限制内,并将任何错误记录到 Excel 中。下面的代码似乎可以正常工作,但只是我在控制台日志中看到的 5 个错误中的最后一个没有出现在输出的 CSV 中。
我尝试了一系列替代方法,包括将 csvWriter 调用放在 .then 而不是 .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
承诺不会等待用户删除操作完成,并且脚本几乎在它开始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))
推荐阅读
- php - openssl_encrypt(): iv key pass is 24 bytes long 这比预期的 16 长
- php - 扩展 Whoops PrettyPageHandler 时的属性 null
- css - CSS Grid - 如何让图像填充网格项空间
- java - 获取 InputMismatchException
- python-3.x - aiohttp:如何最好地缓解“OSError:打开的文件太多”
- runtime-error - appmaker:我收到错误 com.google.web.bindery.event.shared.UmbrellaException:异常捕获:路径段不存在
- docker - 使用两个 docker compose 在容器之间的 docker 网络中调用 web api
- hive - Airflow HiveCliHook 连接到远程配置单元集群?
- python - 使用 LLVMlite 的 LLVM 中的断言失败
- ssis - 是否可以使用 SISS 连接到 adobe 分析 API