Skip to content

feat: add developer inactivity alerts#4868

Open
wescopeland wants to merge 4 commits into
RetroAchievements:masterfrom
wescopeland:dev-inactivity-alerts
Open

feat: add developer inactivity alerts#4868
wescopeland wants to merge 4 commits into
RetroAchievements:masterfrom
wescopeland:dev-inactivity-alerts

Conversation

@wescopeland
Copy link
Copy Markdown
Member

@wescopeland wescopeland commented May 9, 2026

https://discord.com/channels/476211979464343552/1002688331827658774/1498772708413149294

This PR adds support for surfacing developer inactivity alerts into a Discord feed channel. Users with a junior developer, moderator, or admin role are excluded from this check.

The alert checks for:

  • overall site activity (users.last_updated_at)
  • publishing new memory notes, achievements, or leaderboards
  • updating any kind of trigger logic
  • creating a new claim of any kind
  • commenting on a ticket
  • resolving a ticket

If the developer is site-inactive for 3 months, an alert will surface. If the developer doesn't have any of the above activities recorded for 6 months, an alert will surface.

The alerts are driven by a nightly scheduled command. Results are cached in Redis so the same alert doesn't pop multiple times.

@wescopeland wescopeland requested a review from a team May 9, 2026 13:38
Comment on lines +148 to +162
$schedule->command(UpdateBeatenGamesLeaderboard::class)->everyFiveMinutes();

$schedule->command(UpdatePlayerPointsStats::class, ['--existing-only'])->hourly();
$schedule->command(UpdateSearchIndexForQueuedEntities::class)->hourly();
$schedule->command(ProcessExpiringClaims::class)->hourly();

$schedule->command(UpdateAwardsStaticData::class)->everyFourHours();

$schedule->command(PruneGameRecentPlayers::class)->daily();
$schedule->command(DeleteStalePlayerPointsStatsEntries::class)->weekly();
$schedule->command(CheckDeveloperInactivity::class)->daily();
$schedule->command(CheckForAchievementSetChanges::class)->daily();

if (app()->environment() === 'production') {
$schedule->command(UpdateAwardsStaticData::class)->everyFourHours();
$schedule->command(UpdateBeatenGamesLeaderboard::class)->everyFiveMinutes();
$schedule->command(UpdatePlayerPointsStats::class, ['--existing-only'])->hourly();
$schedule->command(ProcessExpiringClaims::class)->hourly();
$schedule->command(UpdateDeveloperContributionYield::class)->weeklyOn(2, '10:00'); // Tuesdays at 10AM UTC
$schedule->command(CrawlPlayerWeightedPoints::class)->weeklyOn(3, '10:00'); // Wednesdays at 10AM UTC
$schedule->command(CheckForAchievementSetChanges::class)->daily();
}
$schedule->command(DeleteStalePlayerPointsStatsEntries::class)->weekly();
$schedule->command(UpdateDeveloperContributionYield::class)->weeklyOn(2, '10:00'); // Tuesdays at 10AM UTC
$schedule->command(CrawlPlayerWeightedPoints::class)->weeklyOn(3, '10:00'); // Wednesdays at 10AM UTC
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Sorted these around and removed the production conditional on several of them (no longer needed now that we have a dedicated stage server).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assumed the environment check was so they don't run in the local environment. I hadn't really considered not wanting to run them in stage.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yep, purely here as a guard against stage.

These shouldn't ever run locally. On our app server, we have a cron that runs every 60 seconds:

php artisan schedule:run

This Laravel built-in command checks if there are any scheduled commands that are due for execution and executes what's ready to go.

Comment thread app/Platform/Actions/DetectInactiveDevelopersAction.php Outdated
Comment thread app/Platform/Actions/DetectInactiveDevelopersAction.php
Comment on lines +148 to +162
$schedule->command(UpdateBeatenGamesLeaderboard::class)->everyFiveMinutes();

$schedule->command(UpdatePlayerPointsStats::class, ['--existing-only'])->hourly();
$schedule->command(UpdateSearchIndexForQueuedEntities::class)->hourly();
$schedule->command(ProcessExpiringClaims::class)->hourly();

$schedule->command(UpdateAwardsStaticData::class)->everyFourHours();

$schedule->command(PruneGameRecentPlayers::class)->daily();
$schedule->command(DeleteStalePlayerPointsStatsEntries::class)->weekly();
$schedule->command(CheckDeveloperInactivity::class)->daily();
$schedule->command(CheckForAchievementSetChanges::class)->daily();

if (app()->environment() === 'production') {
$schedule->command(UpdateAwardsStaticData::class)->everyFourHours();
$schedule->command(UpdateBeatenGamesLeaderboard::class)->everyFiveMinutes();
$schedule->command(UpdatePlayerPointsStats::class, ['--existing-only'])->hourly();
$schedule->command(ProcessExpiringClaims::class)->hourly();
$schedule->command(UpdateDeveloperContributionYield::class)->weeklyOn(2, '10:00'); // Tuesdays at 10AM UTC
$schedule->command(CrawlPlayerWeightedPoints::class)->weeklyOn(3, '10:00'); // Wednesdays at 10AM UTC
$schedule->command(CheckForAchievementSetChanges::class)->daily();
}
$schedule->command(DeleteStalePlayerPointsStatsEntries::class)->weekly();
$schedule->command(UpdateDeveloperContributionYield::class)->weeklyOn(2, '10:00'); // Tuesdays at 10AM UTC
$schedule->command(CrawlPlayerWeightedPoints::class)->weeklyOn(3, '10:00'); // Wednesdays at 10AM UTC
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assumed the environment check was so they don't run in the local environment. I hadn't really considered not wanting to run them in stage.

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