| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- package service
- import (
- "context"
- "fmt"
- "time"
- "github.com/robfig/cron/v3"
- )
- var scheduledTestCronParser = cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
- // ScheduledTestService provides CRUD operations for scheduled test plans and results.
- type ScheduledTestService struct {
- planRepo ScheduledTestPlanRepository
- resultRepo ScheduledTestResultRepository
- }
- // NewScheduledTestService creates a new ScheduledTestService.
- func NewScheduledTestService(
- planRepo ScheduledTestPlanRepository,
- resultRepo ScheduledTestResultRepository,
- ) *ScheduledTestService {
- return &ScheduledTestService{
- planRepo: planRepo,
- resultRepo: resultRepo,
- }
- }
- // CreatePlan validates the cron expression, computes next_run_at, and persists the plan.
- func (s *ScheduledTestService) CreatePlan(ctx context.Context, plan *ScheduledTestPlan) (*ScheduledTestPlan, error) {
- nextRun, err := computeNextRun(plan.CronExpression, time.Now())
- if err != nil {
- return nil, fmt.Errorf("invalid cron expression: %w", err)
- }
- plan.NextRunAt = &nextRun
- if plan.MaxResults <= 0 {
- plan.MaxResults = 50
- }
- return s.planRepo.Create(ctx, plan)
- }
- // GetPlan retrieves a plan by ID.
- func (s *ScheduledTestService) GetPlan(ctx context.Context, id int64) (*ScheduledTestPlan, error) {
- return s.planRepo.GetByID(ctx, id)
- }
- // ListPlansByAccount returns all plans for a given account.
- func (s *ScheduledTestService) ListPlansByAccount(ctx context.Context, accountID int64) ([]*ScheduledTestPlan, error) {
- return s.planRepo.ListByAccountID(ctx, accountID)
- }
- // UpdatePlan validates cron and updates the plan.
- func (s *ScheduledTestService) UpdatePlan(ctx context.Context, plan *ScheduledTestPlan) (*ScheduledTestPlan, error) {
- nextRun, err := computeNextRun(plan.CronExpression, time.Now())
- if err != nil {
- return nil, fmt.Errorf("invalid cron expression: %w", err)
- }
- plan.NextRunAt = &nextRun
- return s.planRepo.Update(ctx, plan)
- }
- // DeletePlan removes a plan and its results (via CASCADE).
- func (s *ScheduledTestService) DeletePlan(ctx context.Context, id int64) error {
- return s.planRepo.Delete(ctx, id)
- }
- // ListResults returns the most recent results for a plan.
- func (s *ScheduledTestService) ListResults(ctx context.Context, planID int64, limit int) ([]*ScheduledTestResult, error) {
- if limit <= 0 {
- limit = 50
- }
- return s.resultRepo.ListByPlanID(ctx, planID, limit)
- }
- // SaveResult inserts a result and prunes old entries beyond maxResults.
- func (s *ScheduledTestService) SaveResult(ctx context.Context, planID int64, maxResults int, result *ScheduledTestResult) error {
- result.PlanID = planID
- if _, err := s.resultRepo.Create(ctx, result); err != nil {
- return err
- }
- return s.resultRepo.PruneOldResults(ctx, planID, maxResults)
- }
- func computeNextRun(cronExpr string, from time.Time) (time.Time, error) {
- sched, err := scheduledTestCronParser.Parse(cronExpr)
- if err != nil {
- return time.Time{}, err
- }
- return sched.Next(from), nil
- }
|