Add clear stuck jobs admin feature and simplify worker scheduling
- Add POST /api/admin/settings/clear-stuck-jobs endpoint to clear stuck/failed asynq worker jobs from Redis (retry queue, archived, orphaned task metadata) - Add "Clear Stuck Jobs" button to admin settings UI - Remove TASK_REMINDER_MINUTE config - all jobs now run at minute 0 - Simplify formatCron to only take hour parameter - Update default notification times to CST-friendly hours 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,10 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/rs/zerolog/log"
|
||||
@@ -105,21 +105,21 @@ func main() {
|
||||
scheduler := asynq.NewScheduler(redisOpt, nil)
|
||||
|
||||
// Schedule task reminder notifications
|
||||
reminderCron := formatCron(cfg.Worker.TaskReminderHour, cfg.Worker.TaskReminderMinute)
|
||||
reminderCron := formatCron(cfg.Worker.TaskReminderHour)
|
||||
if _, err := scheduler.Register(reminderCron, asynq.NewTask(jobs.TypeTaskReminder, nil)); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to register task reminder job")
|
||||
}
|
||||
log.Info().Str("cron", reminderCron).Msg("Registered task reminder job")
|
||||
|
||||
// Schedule overdue reminder at 9 AM UTC
|
||||
overdueCron := formatCron(cfg.Worker.OverdueReminderHour, 0)
|
||||
// Schedule overdue reminder
|
||||
overdueCron := formatCron(cfg.Worker.OverdueReminderHour)
|
||||
if _, err := scheduler.Register(overdueCron, asynq.NewTask(jobs.TypeOverdueReminder, nil)); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to register overdue reminder job")
|
||||
}
|
||||
log.Info().Str("cron", overdueCron).Msg("Registered overdue reminder job")
|
||||
|
||||
// Schedule daily digest at 11 AM UTC
|
||||
dailyCron := formatCron(cfg.Worker.DailyNotifHour, 0)
|
||||
// Schedule daily digest
|
||||
dailyCron := formatCron(cfg.Worker.DailyNotifHour)
|
||||
if _, err := scheduler.Register(dailyCron, asynq.NewTask(jobs.TypeDailyDigest, nil)); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to register daily digest job")
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func main() {
|
||||
log.Info().Msg("Worker stopped")
|
||||
}
|
||||
|
||||
// formatCron creates a cron expression for a specific hour and minute (UTC)
|
||||
func formatCron(hour, minute int) string {
|
||||
return time.Date(0, 1, 1, hour, minute, 0, 0, time.UTC).Format("4 15 * * *")
|
||||
// formatCron creates a cron expression for a specific hour (runs at minute 0)
|
||||
func formatCron(hour int) string {
|
||||
return fmt.Sprintf("0 %02d * * *", hour)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user