package main
import (
"errors"
"fmt"
"log"
"os"
"os/signal"
"runtime"
"sync"
"time"
)
type Runner struct {
interrrupt chan os.Signal
complete chan error
timeout <-chan time.Time
tasks []func(int)
}
var ErrorTimeout = errors.New("received timeout")
var ErrorInterrupt = errors.New("received interrupt")
func New(d time.Duration) * Runner{
return &Runner{
interrrupt:make(chan os.Signal,1),
complete:make(chan error),
timeout:time.After(d),
}
}
func (r *Runner) Add(tasks ...func(int)) {
r.tasks = append(r.tasks,tasks...)
}
func (r *Runner) Start() error {
signal.Notify(r.interrrupt,os.Interrupt);
go func(){
r.complete<- r.run()
}()
select {
case err:= <-r.complete:
return err
case <-r.timeout:
return ErrorTimeout
}
}
func (r *Runner) run() error {
for id,task:= range r.tasks{
if r.gotInterrupt(){
return ErrorInterrupt
}
task(id)
}
return nil
}
func (r *Runner) gotInterrupt() bool {
select {
case <- r.interrrupt:
signal.Stop(r.interrrupt)
return true
default:
return false
}
}
const timeout = 3* time.Second
func createTask() func(int) {
return func(id int) {
log.Printf("Processsor -Task #%d.",id)
time.Sleep(time.Duration(id)*time.Second)
}
}
func main(){
log.Println("Start work")
r:= New(timeout)
r.Add( createTask(),createTask(),createTask())
if err:= r.Start(); err!=nil{
switch err {
case ErrorTimeout:
log.Println("Terminating due to timeout")
os.Exit(1)
case ErrorInterrupt:
log.Println("Terminating due to interrupt")
os.Exit(2)
}
}
log.Println("Proceess ended")
}