package usecase import ( "errors" "fmt" "sync" "time" ) type BuildInstruction struct { SolutionId int32 BindingKey string Language int32 Solution string } type BuildResult struct { SolutionId int32 BindingKey string Status int32 } type RunInstruction struct { SolutionId int32 TestId int32 BindingKey string } type RunResult struct { SolutionId int32 TestId int32 BindingKey string Status int32 } type RunnerUseCase struct { freeProcesses int32 mtx sync.RWMutex results chan interface{} } func NewRunnerUseCase(limit int32) *RunnerUseCase { return &RunnerUseCase{ freeProcesses: limit, results: make(chan interface{}), } } func (uc *RunnerUseCase) Process(i interface{}) error { uc.mtx.Lock() defer uc.mtx.Unlock() if uc.freeProcesses == 0 { return errors.New("no free processes") } uc.freeProcesses-- go func(i interface{}) { defer func() { uc.mtx.Lock() uc.freeProcesses++ uc.mtx.Unlock() }() switch instruction := i.(type) { case RunInstruction: fmt.Println("running: ", instruction.SolutionId, instruction.TestId) time.Sleep(time.Second) uc.results <- RunResult{ SolutionId: instruction.SolutionId, TestId: instruction.TestId, BindingKey: instruction.BindingKey, Status: 0, } case BuildInstruction: fmt.Println("building:", instruction.Language, instruction.Solution) time.Sleep(time.Second) uc.results <- BuildResult{ SolutionId: instruction.SolutionId, BindingKey: instruction.BindingKey, Status: -1, } default: fmt.Println("unknown instruction ignored") } }(i) return nil } func (uc *RunnerUseCase) Results() <-chan interface{} { return uc.results } // Ready is not thread safe! func (uc *RunnerUseCase) Ready() bool { return uc.freeProcesses > 0 } func (uc *RunnerUseCase) Lock() { uc.mtx.Lock() } func (uc *RunnerUseCase) Unlock() { uc.mtx.Unlock() }