āϏāĻŽāϝāĻŧāϏ⧂āĻšā§€ āĻĢāĻžāĻ‚āĻļāύ

āφāĻĒāύāĻŋ āϝāĻĻāĻŋ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āϏāĻŽāϝāĻŧ⧇ āϚāĻžāϞāĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āĻĢāĻžāĻ‚āĻļāύ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŖ āĻ•āϰāϤ⧇ āϚāĻžāύ, firebase-functions/v2/scheduler āĻĻā§āĻŦāĻžāϰāĻž āĻĒā§āϰāĻĻāĻ¤ā§āϤ onSchedule āĻšā§āϝāĻžāĻ¨ā§āĻĄāϞāĻžāϰ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύāĨ¤ āĻāχ āĻĢāĻžāĻ‚āĻļāύāϗ⧁āϞāĻŋ Cloud Scheduler āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āφāĻĒāύāĻžāϰ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āϏāĻŽāϝāĻŧ āĻŦāĻž āĻŦā§āϝāĻŦāϧāĻžāύ⧇ āĻĢāĻžāĻ‚āĻļāύ āϞāϜāĻŋāĻ• āϚāĻžāϞ⧁ āĻ•āϰāϤ⧇āĨ¤

āφāĻĒāύāĻŋ āĻļ⧁āϰ⧁ āĻ•āϰāĻžāϰ āφāϗ⧇

āϝāĻĻāĻŋāĻ“ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŋāϤ āĻĢāĻžāĻ‚āĻļāύāϗ⧁āϞāĻŋ āĻŦāĻŋāϞ āĻ•āϰāĻž āĻšāϝāĻŧ, āφāĻĒāύāĻŋ āϏāĻžāĻŽāĻ—ā§āϰāĻŋāĻ• āĻ–āϰāϚ āĻĒāϰāĻŋāϚāĻžāϞāύāĻžāϝ⧋āĻ—ā§āϝ āĻšāĻŦ⧇ āĻŦāϞ⧇ āφāĻļāĻž āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύ, āĻ•āĻžāϰāĻŖ āĻĒā§āϰāϤāĻŋāϟāĻŋ Cloud Scheduler āĻ•āĻžāĻœā§‡āϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāϤāĻŋ āĻŽāĻžāϏ⧇ $0.10 (USD) āĻ–āϰāϚ āĻšāϝāĻŧ āĻāĻŦāĻ‚ āĻĒā§āϰāϤāĻŋ Google āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡ āϤāĻŋāύāϟāĻŋ āĻ•āĻžāĻœā§‡āϰ āĻ­āĻžāϤāĻž āϰāϝāĻŧ⧇āϛ⧇, āϕ⧋āύ⧋ āϚāĻžāĻ°ā§āϜ āĻ›āĻžāĻĄāĻŧāĻžāχ⧎ āφāĻĒāύāĻžāϰ āĻ…āύ⧁āĻŽāĻžāύ āĻ•āϰāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ⧇āϰ āωāĻĒāϰ āĻ­āĻŋāĻ¤ā§āϤāĻŋ āĻ•āϰ⧇ āĻāĻ•āϟāĻŋ āĻ–āϰāϚ āĻ…āύ⧁āĻŽāĻžāύ āϤ⧈āϰāĻŋ āĻ•āϰāϤ⧇ āĻŦā§āϞ⧇āϜ āĻĒā§āϰāĻžāχāϏāĻŋāĻ‚ āĻ•ā§āϝāĻžāϞāϕ⧁āϞ⧇āϟāϰ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύāĨ¤

āφāĻĒāύāĻžāϰ āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡āϰ āϜāĻ¨ā§āϝ Cloud Scheduler āĻāĻĒāĻŋāφāχ āϏāĻ•ā§āώāĻŽ āĻ•āϰāĻž āφāĻŦāĻļā§āϝāĻ•āĨ¤ āĻŦ⧇āĻļāĻŋāϰāĻ­āĻžāĻ— āĻĢāĻžāϝāĻŧāĻžāϰāĻŦ⧇āϏ āĻĒā§āϰāĻ•āĻ˛ā§āĻĒ⧇āϰ āϜāĻ¨ā§āϝ āĻāϟāĻŋ āχāϤāĻŋāĻŽāĻ§ā§āϝ⧇āχ āϏāĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āωāϚāĻŋāϤ; āφāĻĒāύāĻŋ Google āĻ•ā§āϞāĻžāωāĻĄ āĻ•āύāϏ⧋āϞ⧇ āϝāĻžāϚāĻžāχ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤

āĻāĻ•āϟāĻŋ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŋāϤ āĻĢāĻžāĻ‚āĻļāύ āϞāĻŋāϖ⧁āύ

Cloud Functions for Firebase āĻ, āϏāĻŽāϝāĻŧāϏ⧂āĻšā§€ āϞāϜāĻŋāĻ• āφāĻĒāύāĻžāϰ āĻĢāĻžāĻ‚āĻļāύ āϕ⧋āĻĄā§‡ āĻĨāĻžāϕ⧇, āϕ⧋āύ⧋ āĻŦāĻŋāĻļ⧇āώ āĻ¸ā§āĻĨāĻžāĻĒāύ-āϏāĻŽāϝāĻŧ⧇āϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ⧀āϝāĻŧāϤāĻž āĻ›āĻžāĻĄāĻŧāĻžāχāĨ¤ āωāĻĻāĻžāĻšāϰāĻŖāĻ¸ā§āĻŦāϰ⧂āĻĒ, āĻĒā§āϰāϤāĻŋāĻĻāĻŋāύ āĻāĻ•āĻŦāĻžāϰ āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟāϗ⧁āϞāĻŋ āĻĒāϰāĻŋāĻˇā§āĻ•āĻžāϰ āĻ•āϰāϤ⧇, āφāĻĒāύāĻŋ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āφāĻŽāĻĻāĻžāύāĻŋ āĻŦāĻŋāĻŦ⧃āϤāĻŋ āĻĻāĻŋāϝāĻŧ⧇ āĻļ⧁āϰ⧁ āĻ•āϰ⧇ āĻāĻ•āϟāĻŋ āĻĢāĻžāĻ‚āĻļāύ āϞāĻŋāĻ–āϤ⧇ āĻĒāĻžāϰ⧇āύ:

Node.js

// The Cloud Functions for Firebase SDK to set up triggers and logging.
const {onSchedule} = require("firebase-functions/v2/scheduler");
const {logger} = require("firebase-functions");

// The Firebase Admin SDK to delete inactive users.
const admin = require("firebase-admin");
admin.initializeApp();

// The es6-promise-pool to limit the concurrency of promises.
const PromisePool = require("es6-promise-pool").default;
// Maximum concurrent account deletions.
const MAX_CONCURRENT = 3;

āĻĒāĻžāχāĻĨāύ

# The Cloud Functions for Firebase SDK to set up triggers and logging.
from firebase_functions import scheduler_fn

# The Firebase Admin SDK to delete users.
import firebase_admin
from firebase_admin import auth

firebase_admin.initialize_app()

āϤāĻžāϰāĻĒāϰ⧇, āφāĻĒāύāĻŋ āĻāĻ•āϟāĻŋ Cloud Scheduler āϟāĻžāĻ¸ā§āĻ• āĻļ⧁āϰ⧁ āĻ•āϰāϤ⧇ onSchedule āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύ:

Node.js

// Run once a day at midnight, to clean up the users
// Manually run the task here https://console.cloud.google.com/cloudscheduler
exports.accountcleanup = onSchedule("every day 00:00", async (event) => {
  // Fetch all user details.
  const inactiveUsers = await getInactiveUsers();

  // Use a pool so that we delete maximum `MAX_CONCURRENT` users in parallel.
  const promisePool = new PromisePool(
      () => deleteInactiveUser(inactiveUsers),
      MAX_CONCURRENT,
  );
  await promisePool.start();

  logger.log("User cleanup finished");
});

āĻĒāĻžāχāĻĨāύ

# Run once a day at midnight, to clean up inactive users.
# Manually run the task here https://console.cloud.google.com/cloudscheduler
@scheduler_fn.on_schedule(schedule="every day 00:00")
def accountcleanup(event: scheduler_fn.ScheduledEvent) -> None:
    """Delete users who've been inactive for 30 days or more."""
    user_page: auth.ListUsersPage | None = auth.list_users()
    while user_page is not None:
        inactive_uids = [
            user.uid for user in user_page.users if is_inactive(user, timedelta(days=30))
        ]
        auth.delete_users(inactive_uids)
        user_page = user_page.get_next_page()

āχāωāύāĻŋāĻ•ā§āϏ āĻ•ā§āϰāĻ¨ā§āϟāĻžāĻŦ āĻāĻŦāĻ‚ App Engine āϏāĻŋāύāĻŸā§āϝāĻžāĻ•ā§āϏ āωāĻ­āϝāĻŧāχ Cloud Scheduler āĻĻā§āĻŦāĻžāϰāĻž āϏāĻŽāĻ°ā§āĻĨāĻŋāϤāĨ¤ āωāĻĻāĻžāĻšāϰāĻŖāĻ¸ā§āĻŦāϰ⧂āĻĒ, āĻ•ā§āϰāĻ¨ā§āϟāĻžāĻŦ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇, āĻāχāϰāĻ•āĻŽ āĻ•āĻŋāϛ⧁ āĻ•āϰ⧁āύ:

Node.js

exports.scheduledFunctionCrontab = onSchedule("5 11 * * *", async (event) => {
  // ...
});

āĻĒāĻžāχāĻĨāύ

@scheduler_fn.on_schedule(schedule="5 11 * * *")

āĻāĻ•āϟāĻŋ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŋāϤ āĻĢāĻžāĻ‚āĻļāύ āĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ

āϝāĻ–āύ āφāĻĒāύāĻŋ āĻāĻ•āϟāĻŋ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŋāϤ āĻĢāĻžāĻ‚āĻļāύ āĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧇āύ, āĻāĻ•āϟāĻŋ āĻļāĻŋāĻĄāĻŋāωāϞāĻžāϰ āĻ•āĻžāϜ āĻāĻŦāĻ‚ āĻāĻ•āϟāĻŋ HTTP āĻĢāĻžāĻ‚āĻļāύ āĻ¸ā§āĻŦāϝāĻŧāĻ‚āĻ•ā§āϰāĻŋāϝāĻŧāĻ­āĻžāĻŦ⧇ āϤ⧈āϰāĻŋ āĻšāϝāĻŧāĨ¤ Firebase CLI āĻĢāĻžāĻ‚āĻļāύ⧇āϰ āύāĻžāĻŽā§‡āϰ āĻĒā§āϰāϤāĻŋāĻ§ā§āĻŦāύāĻŋ āĻ•āϰ⧇, āĻāĻŦāĻ‚ āφāĻĒāύāĻŋ Google āĻ•ā§āϞāĻžāωāĻĄ āĻ•āύāϏ⧋āϞ⧇ āĻ•āĻžāϜ āĻāĻŦāĻ‚ āĻĢāĻžāĻ‚āĻļāύ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āύāϭ⧇āύāĻļāύ āĻ…āύ⧁āϏāĻžāϰ⧇ āĻŦāĻŋāώāϝāĻŧāϟāĻŋāϰ āύāĻžāĻŽāĻ•āϰāĻŖ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇:

āĻĢāĻžāϝāĻŧāĻžāϰāĻŦ⧇āϏ-āĻļāĻŋāĻĄāĻŋāωāϞ- function_name - region

āϝ⧇āĻŽāύ:

firebase-shedule-accountcleanup-us-east1.

āύāĻŋāĻ°ā§āϧāĻžāϰāĻŋāϤ āϏāĻŽāϝāĻŧ⧇, āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ—āĻŖāύāĻž āĻĒāϰāĻŋāώ⧇āĻŦāĻž āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āϏāĻ‚āĻļā§āϞāĻŋāĻˇā§āϟ HTTP āĻĢāĻžāĻ‚āĻļāύāϕ⧇ āφāĻšā§āĻŦāĻžāύ āĻ•āϰ⧇āĨ¤ āĻāϰ āĻŽāĻžāύ⧇ āĻšāϞ āϝ⧇ āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āϝ⧁āĻ•ā§āϤ Cloud Scheduler āĻ•āĻžāĻœā§‡āϰ āĻĢāĻžāĻ‚āĻļāύ āϚāĻžāϞāĻžāύ⧋āϰ āĻ…āύ⧁āĻŽāϤāĻŋ āφāϛ⧇āĨ¤