在所有setTimeout完成之后,节点脚本不会退出

时间:2019-11-13 18:47:02

标签: javascript node.js firebase firebase-authentication firebase-admin

我有这个脚本,可以更改我们用于测试目的的现有FireBase身份验证用户的所有密码,以将用户重置为“干净”状态。

var admin = require('firebase-admin');

// Input args
var jsonKey = process.argv[2];
var projectId = process.argv[3];
var newPassword = process.argv[4];

var serviceAccount = require(jsonKey);

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://" + projectId + ".firebaseio.com"
});

// FIXME Only for debug purposes
var index = 1;

/**
* https://firebase.google.com/docs/auth/admin/manage-users#update_a_user
*/
function nextUser(uid, timeout) { 
    setTimeout(() => {
        admin.auth().updateUser(uid, { 
            password : newPassword
        })
        .then(function() {
            console.log(index++ + ') Successfully updated user', uid);
        })
        .catch(function(error) {
            console.log(index++ + ') Error updating user:', error);
        });
    }, timeout);
}

/**
* https://firebase.google.com/docs/auth/admin/manage-users#list_all_users
* https://stackoverflow.com/a/58028558
*/
function listAllUsers(nextPageToken) {
    let timeout = 0;
    admin.auth().listUsers(1000, nextPageToken)
        .then(function (listUsersResult) {
            console.log("Retrieved " + listUsersResult.users.length + " users");

            listUsersResult.users.forEach(function (userRecord) {
                timeout = timeout + 100
                nextUser(userRecord.uid, timeout)
            });

            if (listUsersResult.pageToken) {
                listAllUsers(listUsersResult.pageToken);
            }
        })
        .catch(function (error) {
            console.log('Error listing users:', error);
        });
}

listAllUsers();

该脚本从本地计算机使用

启动
node <filename.js> <path of jsonkey> <projectid> <new password>

您可以看到迭代器正在超时运行,这是在我遇到“我试图用this answer解决的“更新帐户信息的配额超出限额”问题后进行的。

脚本运行正常,所有用户都得到了正确处理(我仅为这种调试添加了顺序计数器),没有抛出“ quota”错误。问题是在脚本末尾,shell提示符没有退出,进程仍然挂起,我需要一个CTRL+C来杀死它。除了这种行为令人讨厌的部分之外,这还阻止了一个更广泛的脚本,该脚本将调用此脚本,并且不会继续执行下一行命令。

似乎在执行所有setTimeout函数之后,主进程不会自动关闭。

我该如何解决?


编辑

我尝试了不同的方法:

第二个版本有效,但是速度很慢。因此,我从初始脚本开始,添加了一个“监视器”,等待所有用户完成操作(计数器非常脏),最后关闭脚本

var admin = require('firebase-admin');

// Input args
var jsonKey = process.argv[2];
var projectId = process.argv[3];
var newPassword = process.argv[4];

var serviceAccount = require(jsonKey);

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://" + projectId + ".firebaseio.com"
});

// Index to count all users that have been queued for processing
var queued = 0;

// Index to count all user that have completed the task
var completed = 0;

/**
* https://firebase.google.com/docs/auth/admin/manage-users#update_a_user
*/
function nextUser(uid, timeout) { 
    setTimeout(() => {

        /* ------ Process User Implementation ------ */
        admin.auth().updateUser(uid, { 
            password : newPassword
        })
        .then(function() {
            console.log(++completed + ') Successfully updated user ', uid);
        })
        .catch(function(error) {
            console.log(++completed + ') Error updating user:', error);
        });
        /* ------ Process User Implementation ------ */

    }, timeout);

    queued++;
}

/**
* https://firebase.google.com/docs/auth/admin/manage-users#list_all_users
* https://stackoverflow.com/a/58028558
*/
function listAllUsers(nextPageToken) {
    let timeout = 0;
    admin.auth().listUsers(1000, nextPageToken)
        .then(function (listUsersResult) {
            console.log("Retrieved " + listUsersResult.users.length + " users");

            listUsersResult.users.forEach(function (userRecord) {
                timeout = timeout + 100
                nextUser(userRecord.uid, timeout)
            });

            if (listUsersResult.pageToken) {
                listAllUsers(listUsersResult.pageToken);
            } else {
                waitForEnd();
            }
        })
        .catch(function (error) {
            console.log('Error listing users:', error);
        });
}

function waitForEnd() {
    if(completed < queued) {
        console.log("> " + completed + "/" + queued + " completed, waiting...");
        setTimeout(waitForEnd, 5000);
    } else {
        console.log("> " + completed + "/" + queued + " completed, exiting...");
        admin.app().delete();
    }
}

listAllUsers();

有效,快速。对我来说足够了,因为它是测试脚本?

1 个答案:

答案 0 :(得分:0)

尝试在setTimeout函数中放置以下退出代码。

process.exit() // exit

我更新了代码。

function listAllUsers(nextPageToken) {
    let timeout = 0;
    admin.auth().listUsers(1000, nextPageToken)
        .then(function (listUsersResult) {
            console.log("Retrieved " + listUsersResult.users.length + " users");

            listUsersResult.users.forEach(function (userRecord) {
                timeout = timeout + 100
                nextUser(userRecord.uid, timeout)
            });

            if (listUsersResult.pageToken) {
                listAllUsers(listUsersResult.pageToken);
            }
            process.exit(0); // exit script with success
        })
        .catch(function (error) {
            console.log('Error listing users:', error);
            process.exit(1); // exit script with failure
        });
}

此函数将退出Node.js脚本。

process.exit([code]) 用指定的代码结束进程。如果省略,则退出使用“成功”代码0。

要以“失败”代码退出:

process.exit(1);

执行节点的外壳应将退出代码视为1。

官方文档:https://nodejs.org/api/process.html#process_exit_codes