Skip to content

feat(auth): automate inactive account notification enqueue#20581

Draft
dschom wants to merge 1 commit into
mainfrom
worktree-FXA-13709
Draft

feat(auth): automate inactive account notification enqueue#20581
dschom wants to merge 1 commit into
mainfrom
worktree-FXA-13709

Conversation

@dschom
Copy link
Copy Markdown
Contributor

@dschom dschom commented May 12, 2026

Because

  • Manually opening a webservices-infra PR per FXA-13709 for each new batch of inactive accounts is repetitive chore work.

This pull request

  • Removes --start-date, --end-date, --active-by-date, --results-limit from enqueue-inactive-account-deletions.ts; adds --batch-size (default 1000).
  • Each run picks the oldest batchSize candidates (createdAt < two-years-ago, ORDER BY createdAt ASC); the floor advances implicitly as deleted accounts drop out — no DB-tracked cursor.
  • Filters out UIDs that already have an inactiveAccountFirstWarning emailSent event in Firestore before enqueueing, so overlapping runs are safe. Emits accounts.inactive.cron.skipped-already-notified.
  • Wires StatsD, AuthFirestore, and AccountEventsManager into the typedi Container for the script.

Issue that this pull request solves

Closes: FXA-13709

Checklist

  • My commit is GPG signed.
  • If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).
  • I have manually reviewed all AI generated code.

How to review (Optional)

  • Key files/areas to focus on: packages/fxa-auth-server/scripts/delete-inactive-accounts/enqueue-inactive-account-deletions.ts
  • Risky or complex parts: dropping the lower-bound createdAt filter relies on ORDER BY ASC + LIMIT plus the Firestore dedup to converge correctly across runs.

Other information (Optional)

Follow-up in webservices-infra: add a Kubernetes CronJob manifest that invokes this script with --batch-size=<N> --dry-run=false --enqueue-emails=true on a schedule.

Because:
- Manually opening a webservices-infra PR per FXA-13709 for each new
  batch of inactive accounts is repetitive chore work.

This commit:
- Replaces --start-date/--end-date/--active-by-date/--results-limit on
  enqueue-inactive-account-deletions.ts with --batch-size (default 1000).
- Each run picks the oldest N candidates (createdAt < two-years-ago,
  ORDER BY createdAt ASC, LIMIT batchSize); the floor advances
  implicitly as deleted accounts drop out.
- Filters out UIDs that already have an inactiveAccountFirstWarning
  emailSent event in Firestore before enqueueing, making overlapping
  runs safe. Emits accounts.inactive.cron.skipped-already-notified.
- Wires StatsD, AuthFirestore, and AccountEventsManager into the typedi
  Container for the script.

Fixes FXA-13709
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the inactive-account deletion enqueue script to support scheduled batch-based processing and Firestore-based duplicate notification checks.

Changes:

  • Replaces date-range/result-limit CLI options with --batch-size.
  • Adds Firestore/account-events wiring and skips already-sent first-warning emails before enqueueing.
  • Updates script integration tests for new defaults and batch-size validation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
packages/fxa-auth-server/scripts/delete-inactive-accounts/enqueue-inactive-account-deletions.ts Implements batch candidate selection, dependency wiring, and already-notified skip logic.
packages/fxa-auth-server/test/scripts/delete-inactive-accounts/enqueue-inactive-account-deletions.in.spec.ts Updates dry-run assertions and adds non-positive batch-size validation coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +531 to +537
const priorEvents = await accountEventsManager.findEmailEvents(
uid,
'emailSent',
'inactiveAccountFirstWarning',
0,
Date.now()
);
Comment on lines +538 to +541
if (priorEvents && priorEvents.length > 0) {
statsd.increment('accounts.inactive.cron.skipped-already-notified');
debugLog(`Skipping ${uid}: first-warning email already sent.`);
return;
Comment on lines +535 to +536
0,
Date.now()
Comment on lines +136 to +139
'--batch-size [number]',
`The max number of candidate accounts to consider per run. Defaults to ${defaultBatchSize}.`,
(x) => parseInt(x),
defaultResultsLImit
defaultBatchSize
Comment on lines +341 to +347
const accountsQuery = accountWhereAndOrderByQueryBuilder(
startDateTimestamp,
endDateTimestamp,
activeByDateTimestamp
)
.select('accounts.uid')
.limit(batchSize);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants