package worker import ( "context" "errors" "fmt" "sync" "time" ) type ( // Task should watch for context Task interface { Start(context.Context) error } Work struct { Name string Task Task wait time.Duration } TaskPool struct { tasks []*Work } ) const ( format = "2006.01.02 15:04:05" ) func NewTaskPool() *TaskPool { return &TaskPool{} } func (w *Work) run(ctx context.Context) error { // first time fire from the get go timer := time.NewTimer(time.Nanosecond) for { select { case <-ctx.Done(): return ctx.Err() case <-timer.C: now := time.Now() fmt.Printf("[%s] Process starting: %s\n", time.Now().Format(format), w.Name) if err := w.Task.Start(ctx); err != nil && !errors.Is(err, context.Canceled) { since := time.Since(now) fmt.Printf("[%s] Process errored (%s): %s\n", time.Now().Format(format), since.String(), w.Name) return err } else { since := time.Since(now) fmt.Printf("[%s] Process done (%s): %s\n", time.Now().Format(format), since.String(), w.Name) } } timer.Reset(w.wait) } } func (self *TaskPool) AddTask(name string, wait time.Duration, task Task) { self.tasks = append(self.tasks, &Work{ Name: name, Task: task, wait: wait, }) } func (self *TaskPool) Start(ctx context.Context) { var wg sync.WaitGroup wg.Add(len(self.tasks)) for _, w := range self.tasks { go func(w *Work) { _ = w.run(ctx) wg.Done() }(w) } wg.Wait() }