Идиоматический способ перезапустить рутину go

# #go

Вопрос:

У меня есть две рутины, выполняющие две длительные задачи. Есть несколько условий, при которых эти процедуры могут привести к ошибке. Я пытаюсь понять, есть ли способ перезапустить процедуры, как только они выйдут из строя. Я также должен избегать перезапуска, если процедура отменена.

Теперь я добавил приведенный ниже код. Пожалуйста, предложите, является ли это идиоматическим способом сделать это.

 func f1(ctx context.Context) error {
    fmt.Println("[f1] start")
    select {
    case <-ctx.Done():
        fmt.Println("[f1] graceful exit")
        return nil
    }
}

func f2(ctx context.Context) error {
    fmt.Println("[f2] start")
    select {
    case <-time.After(1 * time.Second):
        // simulating an error condition
        fmt.Println("[f2] errored exit")
        return fmt.Errorf("error")
    case <-ctx.Done():
        fmt.Println("[f2] graceful exit")
        return nil
    }
}

func manage(ctx context.Context, f func(ctx context.Context) error) {
    for {
        err := f(ctx)
        if err == nil {
            return
        }
        <-time.After(1 * time.Second)
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())

    go manage(ctx, f1)
    go manage(ctx, f2)

    // delay to see the exeution
    <-time.After(5 * time.Second)
    cancel()
    <-time.After(5 * time.Second)
}
 

Ответ №1:

Для этого не существует идиоматического способа. Процедуры Go не умирают произвольно и не нуждаются в перезапуске.

Либо обработайте ошибку внутри процедуры go и предотвратите ее завершение, либо передайте сообщение об ошибке обратно в точку запуска процедуры, обработайте ее там, а затем повторно запустите процедуру go на разных входах, если это необходимо.

Комментарии:

1. Вот пример этого play.golang.org/p/VqXulsNlmti Поэтому вместо того, чтобы возвращать ошибку, передайте канал ошибок и просто передайте ему ошибки, а не возвращайте, если контекст не отменен. Обратите внимание, что в этом примере, если канал ошибок не используется (как в reportErrors), f2 будет заблокирован на неопределенный срок после его первой ошибки.