package worker import ( "github.com/hibiken/asynq" "github.com/rs/zerolog/log" ) // Task types for email jobs const ( TypeWelcomeEmail = "email:welcome" TypeVerificationEmail = "email:verification" TypePasswordResetEmail = "email:password_reset" TypePasswordChangedEmail = "email:password_changed" ) // EmailPayload is the base payload for email tasks type EmailPayload struct { To string `json:"to"` FirstName string `json:"first_name"` } // WelcomeEmailPayload is the payload for welcome emails type WelcomeEmailPayload struct { EmailPayload ConfirmationCode string `json:"confirmation_code"` } // VerificationEmailPayload is the payload for verification emails type VerificationEmailPayload struct { EmailPayload Code string `json:"code"` } // PasswordResetEmailPayload is the payload for password reset emails type PasswordResetEmailPayload struct { EmailPayload Code string `json:"code"` ResetToken string `json:"reset_token"` } // TaskClient wraps the asynq client for enqueuing tasks type TaskClient struct { client *asynq.Client } // NewTaskClient creates a new task client func NewTaskClient(redisAddr string) *TaskClient { client := asynq.NewClient(asynq.RedisClientOpt{Addr: redisAddr}) return &TaskClient{client: client} } // Close closes the task client func (c *TaskClient) Close() error { return c.client.Close() } // EnqueueWelcomeEmail enqueues a welcome email task func (c *TaskClient) EnqueueWelcomeEmail(to, firstName, code string) error { payload, err := BuildWelcomeEmailPayload(to, firstName, code) if err != nil { return err } task := asynq.NewTask(TypeWelcomeEmail, payload) _, err = c.client.Enqueue(task, asynq.Queue("default"), asynq.MaxRetry(3)) if err != nil { log.Error().Err(err).Str("to", to).Msg("Failed to enqueue welcome email") return err } log.Debug().Str("to", to).Msg("Welcome email task enqueued") return nil } // EnqueueVerificationEmail enqueues a verification email task func (c *TaskClient) EnqueueVerificationEmail(to, firstName, code string) error { payload, err := BuildVerificationEmailPayload(to, firstName, code) if err != nil { return err } task := asynq.NewTask(TypeVerificationEmail, payload) _, err = c.client.Enqueue(task, asynq.Queue("default"), asynq.MaxRetry(3)) if err != nil { log.Error().Err(err).Str("to", to).Msg("Failed to enqueue verification email") return err } log.Debug().Str("to", to).Msg("Verification email task enqueued") return nil } // EnqueuePasswordResetEmail enqueues a password reset email task func (c *TaskClient) EnqueuePasswordResetEmail(to, firstName, code, resetToken string) error { payload, err := BuildPasswordResetEmailPayload(to, firstName, code, resetToken) if err != nil { return err } task := asynq.NewTask(TypePasswordResetEmail, payload) _, err = c.client.Enqueue(task, asynq.Queue("default"), asynq.MaxRetry(3)) if err != nil { log.Error().Err(err).Str("to", to).Msg("Failed to enqueue password reset email") return err } log.Debug().Str("to", to).Msg("Password reset email task enqueued") return nil } // EnqueuePasswordChangedEmail enqueues a password changed confirmation email func (c *TaskClient) EnqueuePasswordChangedEmail(to, firstName string) error { payload, err := BuildPasswordChangedEmailPayload(to, firstName) if err != nil { return err } task := asynq.NewTask(TypePasswordChangedEmail, payload) _, err = c.client.Enqueue(task, asynq.Queue("default"), asynq.MaxRetry(3)) if err != nil { log.Error().Err(err).Str("to", to).Msg("Failed to enqueue password changed email") return err } log.Debug().Str("to", to).Msg("Password changed email task enqueued") return nil }