防止上下文取消在业务逻辑执行过程中停止函数执行。

huangapple go评论84阅读模式
英文:

Prevent context cancel from stopping function execution in the middle of business logic

问题

有没有一种方法可以保护业务逻辑的执行不受上下文取消的影响?以下是一个代码片段,以更好地理解我的问题。

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

func foo(ctx context.Context) {
    // 批量处理数据
    // 上下文取消不应该在业务逻辑的中间停止函数执行
    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

当执行开始进入循环时,它应该一直执行,直到完成该迭代。使用上下文取消是否可能实现这一点?还是我应该使用其他方法?请给予建议。

Go Playground 链接

英文:

Is there a way to safeguard the execution of business logic from context cancel? Here is the code snippet for a better understanding of my problem

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&lt;10; i++ {
		fmt.Println(&quot;START of business logic for ID:&quot;, i)
		fmt.Println(&quot;Critical component&quot;)
		fmt.Print(&quot;Saving changes to DB...&quot;)
		time.Sleep(time.Second * 1)
		fmt.Println(&quot;Done&quot;)
		fmt.Println(&quot;END of business logic for ID:&quot;, i)
	}
}

Output:

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

When the execution starts in the for loop, it should not stop until it finishes that iteration. Is this possible with using context cancel? or should I use another approach, please suggest.

Go Playground Link

答案1

得分: 2

上下文取消是一种向任务发送信号的机制。它不能确保强制执行 - 这取决于任务本身。这允许任务在中止整个操作之前完成关键的子任务。

因此,在你的理论示例中,任何关键的子步骤都应该忽略取消操作 - 只有在它们完成后才轮询上下文:

select {
    case <-ctx.Done():
        return ctx.Err() // 我们被取消了,中止操作
    default:
}

编辑:应用到你的示例

for i := 0; i < 10; i++ {
    //
    // 关键部分
    //

    // ...

    select {
    case <-ctx.Done():
        return ctx.Err() // 我们被取消了,中止操作
    default:
    }
}

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

英文:

Context cancelation is a signal mechanism to a task. It does not ensure enforcement - that is left up to the task. This allows a task to finish up critical sub-tasks before aborting the larger operation.

So in your theoretical example any critical sub-steps should ignore cancelation - and only after they are complete poll the context:

select {
    case &lt;-ctx.Done():
        return ctx.Err() // we&#39;re cancelled, abort
    default:
}

EDIT: applying to your example

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

    // ...

	select {
	case &lt;-ctx.Done():
		return ctx.Err() // we&#39;re cancelled, abort
	default:
	}
}

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

huangapple
  • 本文由 发表于 2021年8月9日 04:36:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/68704573.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定