You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
2.6 KiB
104 lines
2.6 KiB
package scheduler |
|
|
|
import ( |
|
"context" |
|
"time" |
|
|
|
"autostore/internal/application/commands" |
|
"autostore/internal/application/interfaces" |
|
) |
|
|
|
type ExpiredItemsScheduler struct { |
|
handleExpiredItemsCmd *commands.HandleExpiredItemsCommand |
|
logger interfaces.ILogger |
|
ticker *time.Ticker |
|
done chan struct{} |
|
} |
|
|
|
func NewExpiredItemsScheduler( |
|
handleExpiredItemsCmd *commands.HandleExpiredItemsCommand, |
|
logger interfaces.ILogger, |
|
) *ExpiredItemsScheduler { |
|
return &ExpiredItemsScheduler{ |
|
handleExpiredItemsCmd: handleExpiredItemsCmd, |
|
logger: logger, |
|
done: make(chan struct{}), |
|
} |
|
} |
|
|
|
func (s *ExpiredItemsScheduler) Start(ctx context.Context) error { |
|
s.logger.Info(ctx, "Starting expired items scheduler") |
|
|
|
// Process expired items immediately on startup |
|
if err := s.processExpiredItems(ctx); err != nil { |
|
s.logger.Error(ctx, "Failed to process expired items on startup", "error", err) |
|
return err |
|
} |
|
|
|
// Calculate duration until next midnight |
|
now := time.Now() |
|
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) |
|
if now.After(midnight) { |
|
midnight = midnight.Add(24 * time.Hour) |
|
} |
|
durationUntilMidnight := midnight.Sub(now) |
|
|
|
// Start a timer for the first midnight |
|
firstMidnightTimer := time.NewTimer(durationUntilMidnight) |
|
|
|
go func() { |
|
for { |
|
select { |
|
case <-firstMidnightTimer.C: |
|
s.processExpiredItems(ctx) |
|
|
|
// After first midnight, set up daily ticker |
|
s.ticker = time.NewTicker(24 * time.Hour) |
|
firstMidnightTimer.Stop() |
|
|
|
for { |
|
select { |
|
case <-s.ticker.C: |
|
s.processExpiredItems(ctx) |
|
case <-s.done: |
|
s.ticker.Stop() |
|
return |
|
case <-ctx.Done(): |
|
s.ticker.Stop() |
|
return |
|
} |
|
} |
|
case <-s.done: |
|
firstMidnightTimer.Stop() |
|
return |
|
case <-ctx.Done(): |
|
firstMidnightTimer.Stop() |
|
return |
|
} |
|
} |
|
}() |
|
|
|
s.logger.Info(ctx, "Expired items scheduler started", "next_run", midnight.Format(time.RFC3339)) |
|
return nil |
|
} |
|
|
|
func (s *ExpiredItemsScheduler) Stop() error { |
|
s.logger.Info(context.Background(), "Stopping expired items scheduler") |
|
close(s.done) |
|
if s.ticker != nil { |
|
s.ticker.Stop() |
|
} |
|
return nil |
|
} |
|
|
|
func (s *ExpiredItemsScheduler) processExpiredItems(ctx context.Context) error { |
|
s.logger.Info(ctx, "Running scheduled expired items processing") |
|
|
|
if err := s.handleExpiredItemsCmd.Execute(ctx); err != nil { |
|
s.logger.Error(ctx, "Scheduled expired items processing failed", "error", err) |
|
return err |
|
} |
|
|
|
s.logger.Info(ctx, "Scheduled expired items processing completed") |
|
return nil |
|
} |