Предотвратить отмену контекста, чтобы остановить выполнение функции в середине бизнес-логики

avatar
abhijit wakchaure
8 августа 2021 в 20:36
363
1
0

Есть ли способ защитить выполнение бизнес-логики от отмены контекста? Вот фрагмент кода для лучшего понимания моей проблемы

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    go foo(ctx)
    time.Sleep(time.Second * 3)
    cancel()
}

func foo(ctx context.Context) {
    // batch process data
    // context cancel should not stop function execution 
    // in the middle of business logic
    for i:= 0; i<10; i++ {
        fmt.Println("START of business logic for ID:", i)
        fmt.Println("Critical component")
        fmt.Print("Saving changes to DB...")
        time.Sleep(time.Second * 1)
        fmt.Println("Done")
        fmt.Println("END of business logic for ID:", i)
    }
}

Вывод:

START of business logic for ID: 0
Critical component
Saving changes to DB...Done
END of business logic for ID: 0
START of business logic for ID: 1
Critical component
Saving changes to DB...Done
END of business logic for ID: 1
START of business logic for ID: 2
Critical component
Saving changes to DB...Done
END of business logic for ID: 2

Когда выполнение начинается в цикле for, оно не должно останавливаться, пока не завершит эту итерацию. Возможно ли это с использованием отмены контекста? или мне следует использовать другой подход, пожалуйста, предложите.

Ссылка на игровую площадку

Источник
super
8 августа 2021 в 20:45
0

В чем именно заключается ваш вопрос? В вашем примере не используется контекст для вычисления чего-либо, поэтому неясно, в какой части этого вы запутались. Контекстная отмена отправляется по каналу в вашу подпрограмму go, поэтому то, как вы прервете ее выполнение, полностью зависит от вас.

mh-cbon
8 августа 2021 в 20:48
0

он заканчивается, потому что ваша программа существует. Это не имеет ничего общего с контекстом. ты вообще им не пользовался.

abhijit wakchaure
8 августа 2021 в 20:50
0

@super Когда я прерываю, я контролирую, но что происходит, когда я прерываю свою бизнес-логику, то есть внутри цикла for. Я хочу, чтобы go не прерывал выполнение функции, пока она находится внутри цикла.

abhijit wakchaure
8 августа 2021 в 20:53
0

@ mh-cbon извините, в примере я не использовал контекст, но это также применимо к контексту. Например, как я могу предотвратить прерывание выполнения критического кода с помощью go, когда пользователь отменяет HTTP-запрос и контекст отменяется

mh-cbon
8 августа 2021 в 20:58
0

под пользователем вы подразумеваете, что кто-то/что-то попадает на ваш http-сервер?

abhijit wakchaure
8 августа 2021 в 21:00
0

@ mh-cbon да, это одна из возможностей

super
8 августа 2021 в 21:07
0

@abhijitwakchaure Прерывание всегда под вашим контролем. Вы получаете сигнал прерывания от канала и выбираете, какие действия предпринять для прерывания.

colm.anseo
8 августа 2021 в 21:15
0

Как отметил @mh-cbon, программа естественным образом завершает работу независимо от отмены контекста. Лучше запускать задачу из основной горутины, а отмену инициировать из вспомогательной горутины. Ниже приведен пример детской площадки.

abhijit wakchaure
8 августа 2021 в 21:21
0

Спасибо всем за ваши быстрые ответы.

Ответы (1)

avatar
colm.anseo
8 августа 2021 в 20:52
2

Отмена контекста — это сигнальный механизм для задачи. Это не обеспечивает правоприменения - это зависит от задачи. Это позволяет задаче завершить важные подзадачи до прерывания более крупной операции.

Таким образом, в вашем теоретическом примере любые критические подэтапы должны игнорировать отмену - и только после их завершения опрашивать контекст:

select {
    case <-ctx.Done():
        return ctx.Err() // we're cancelled, abort
    default:
}

EDIT: применимо к вашему примеру

for i := 0; i < 10; i++ {
    //
    // critical section
    //

    // ...

    select {
    case <-ctx.Done():
        return ctx.Err() // we're cancelled, abort
    default:
    }
}

https://play.golang.org/p/kZ39VEVyP4L

abhijit wakchaure
8 августа 2021 в 21:01
0

Как я могу использовать мой цикл for для бизнес-логики с выбором? Не могли бы вы поделиться фрагментом, если это возможно?

abhijit wakchaure
8 августа 2021 в 21:24
0

Спасибо @colm.anseo за ссылку на игровую площадку, я отменил для основной.