# #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 будет заблокирован на неопределенный срок после его первой ошибки.