Concurrent Retry Executor

Предадени решения

Краен срок:
15.11.2016 17:30
Точки:
10

Срокът за предаване на решения е отминал

Напишете функция, която конкурентно и последователно изпълнява списък от подадени ѝ задачи и връща техните резултати като канал:

func ConcurrentRetryExecutor(tasks []func() string, concurrentLimit int, retryLimit int) <-chan struct {index int; result string}

Всяка задача от tasks е под формата на проста функция, която връща string като резултат. Ако върнатият string е празен, това се приема за грешка и трябва веднага да изпълните отново задачата. Всяка задача може да бъде изпълнена максимум retryLimit на брой пъти. В даден момент трябва да се изпълняват по concurrentLimit на брой задачи едновременно, ако това е възможно.

Функцията трябва да връща канала без да изчаква извършването на задачите - за това имаме канала.

Резултатите от изпълнението на задачите (вкл. грешните празни отговори) заедно с поредните номера на самите задачи (техният индекс в tasks) трябва да бъдат изпращани по return канала. Този канал трябва да бъде създаден от ConcurrentRetryExecutor и да бъде затворен след като последната задача е приключила и нейният резултат е бил записан в канала.

Също така, трябва да е възможно няколко инстанции на ConcurrentRetryExecutor да работят едновременно, без да си пречат една на друга.

Ето как изглежда това на практика. Следният код:

first := func() string {
    time.Sleep(2 * time.Second)
    return "first"
}
second := func() string {
    time.Sleep(1 * time.Second)
    return "second"
}
third := func() string {
    time.Sleep(600 * time.Millisecond)
    return "" // always a failure :(
}
fourth := func() string {
    time.Sleep(700 * time.Millisecond)
    return "am I last?"
}

fmt.Println("Starting concurrent executor!")
tasks := []func() string{first, second, third, fourth}
results := ConcurrentRetryExecutor(tasks, 2, 3)
for result := range results {
    if result.result == "" {
        fmt.Printf("Task %d returned an error!\n", result.index+1)
    } else {
        fmt.Printf("Task %d successfully returned '%s'\n", result.index+1, result.result)
    }
}
fmt.Println("All done!")

би трябвало да изведе:

Starting concurrent executor!
Task 2 successfully returned 'second'
Task 3 returned an error!
Task 1 successfully returned 'first'
Task 3 returned an error!
Task 4 successfully returned 'am I last?'
Task 3 returned an error!
All done!