首页 > 解决方案 > 所有 setTimeout 完成后节点脚本不退出

问题描述

我有这个脚本可以更改我们用于测试目的的现有 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>

正如您所看到的,迭代器正在超时运行,这是在我遇到“超过更新帐户信息的配额”的问题后需要的,我试图用这个答案解决这个问题

脚本运行良好,所有用户都被正确处理(我只为这种调试添加了一个顺序计数器)并且没有抛出“配额”错误。问题是,在脚本结束时,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();

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

标签: javascriptnode.jsfirebasefirebase-authenticationfirebase-admin

解决方案


尝试将以下退出代码放在 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);

执行节点的 shell 应该看到退出代码为 1。

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


推荐阅读