Quota exceeded when updating users with Firebase Admin SDK - how can I request more?
Asked Answered
S

3

17

We try to update many users in our multitenant setup, when a whole tenant needs to be enabled/disabled. With this, we sometimes run into QUOTA_EXCEEDED errors, especially for large tenants with many users. I have asked how to do this better here: Disable many users at once

As there are currently no bulk operations to update users with the Firebase Admin SDK, how can I request a quota raise?

How can I raise the quota?

Structuralism answered 22/10, 2018 at 9:26 Comment(0)
M
8

firebaser here

If you're running into quota limits that can't be changed from the Firebase console, reach out to Firebase support for personalized help. They can typically help raise quota temporarily, and it's also a great indicator for our engineering team on the need for a feature.

Mellins answered 22/10, 2018 at 13:51 Comment(2)
This quota of user update is not mentioned in auth limits document. It will be helpful for developers to know the default limits in advance to plan and optimize the use case accordingly. I have to contact support for getting the limits of generating email link.Moneychanger
Just hitting this now, and I'd repeat the desire for better documentation about this limit. We don't have that many users, but many happened to join in the same afternoon. By the time we hit this limit and did research, a bunch of stuff broke. Having a critical bit of functionality with a stealth quota and a manual help step is bad.Cordova
T
18

For everybody having the same issue, here is a solution.

I contacted firebase support and got this answer

If you try to update a user’s information at once (more than 10 users or requests per second), then you'll be encountering this error message "Exceeded quota for updating account information". Please note that when we get a huge amount of requests in a short period of time, throttling is applied automatically to protect our servers. You may try sending the requests sequentially (distribute the load) instead of sending them in parallel. So basically, you'll need to process them one at a time (instead of all at once) in order to avoid the error.

So i solved this with a timeout that sends an individual record every 100ms

function listAllUsers(nextPageToken) {
        let timeout = 0;
        admin.auth().listUsers(1000, nextPageToken)
            .then(function (listUsersResult) {
                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();

The nextUser function:

function nextUser(uid, timeout) { 
        setTimeout(() => {
            admin.auth().setCustomUserClaims(uid, { client: true }).then(() => {
            }).catch(function (error) {
                console.log('Error setting user:', error);
            });
        }, timeout);
    }
Trimaran answered 20/9, 2019 at 12:37 Comment(4)
Code is working, I updated all users w/o having quota errors. But after all users has been processed the function remains hanging, I need to manually kill it.Chappie
Found the 100ms to be a bit too tight with occasional throttles, so might want to start with a bit more to avoid having to re-process after catching an error 90% of the way in.Insectivorous
500ms worked error-free if you have the time~Austrasia
I get the error: Promises must be handled appropriately with code similar to this.Epileptic
M
8

firebaser here

If you're running into quota limits that can't be changed from the Firebase console, reach out to Firebase support for personalized help. They can typically help raise quota temporarily, and it's also a great indicator for our engineering team on the need for a feature.

Mellins answered 22/10, 2018 at 13:51 Comment(2)
This quota of user update is not mentioned in auth limits document. It will be helpful for developers to know the default limits in advance to plan and optimize the use case accordingly. I have to contact support for getting the limits of generating email link.Moneychanger
Just hitting this now, and I'd repeat the desire for better documentation about this limit. We don't have that many users, but many happened to join in the same afternoon. By the time we hit this limit and did research, a bunch of stuff broke. Having a critical bit of functionality with a stealth quota and a manual help step is bad.Cordova
M
3

I ran into the same issue mentioned above while updating custom auth claims for all users. I was able to solve it through this alternative implementation of running updates in sequence without relying on timeouts.

This waits for the previous promise to resolve before executing the next update

try {
    const promises = await IterateAllUsers();
    await promises.reduce(async (previousPromise, nextAsyncFunctionPromise) => {
        await previousPromise;
        const nextAsyncFunction = await nextAsyncFunctionPromise
        // Actual execution
        await nextAsyncFunction();
    }, Promise.resolve());
    console.log('done');
} catch(error) {
    console.error(error);
}

Whatever you have to iterate over but it should at least return an Array of Promises of Function to execute later

async function IterateAllUsers(): Promise<Array<Promise<Function>>> {
    const promises: Array<Promise<Function>> = [];
    await // Iterate Authentication Users or Database Collection etc.
    promises.push(updateAuthCustomClaims(user.key, someValue));    
    return Promise.resolve(promises);
}

The higher order function to fill the array with tasks to execute later

async function updateAuthCustomClaims(uid: string, someValue): Promise<Function> {
    return async () => {
        try {
            await admin.auth().setCustomUserClaims(uid,{someValue});
            console.log('Updated user: ', uid);
        } catch(error) {
            console.warn('Could not add custom claim due to: ', error);
        }
        return Promise.resolve();
    };
}
Mailable answered 21/4, 2020 at 10:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.