面试题答案
一键面试设计思路
- 创建上下文:在微服务的入口创建一个
context.Context
,通常使用context.Background()
作为根上下文,然后基于此创建可取消的上下文,如ctx, cancel := context.WithCancel(context.Background())
。这个cancel
函数将用于在接收到取消信号时取消上下文。 - 传递上下文:将创建的上下文传递给每个调用下游服务的子协程。每个子协程在执行下游服务调用时,需要定期检查上下文的取消信号,例如在调用下游服务的函数中使用
ctx.Done()
通道来判断是否已取消。 - 处理取消信号:当收到外部取消信号(例如通过操作系统信号、HTTP 中断等),调用
cancel()
函数取消上下文。所有子协程在检测到上下文取消后,应尽快结束当前操作,释放资源并退出。
关键代码片段(以 Go 语言为例)
package main
import (
"context"
"fmt"
"sync"
"time"
)
// 模拟下游服务调用
func downstreamService(ctx context.Context, name string, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Printf("Service %s received cancel signal, exiting...\n", name)
return
default:
fmt.Printf("Service %s is running...\n", name)
time.Sleep(1 * time.Second)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
// 启动多个子协程调用下游服务
for i := 0; i < 3; i++ {
wg.Add(1)
go downstreamService(ctx, fmt.Sprintf("Service-%d", i), &wg)
}
// 模拟接收到外部取消信号
go func() {
time.Sleep(3 * time.Second)
fmt.Println("Received cancel signal")
cancel()
}()
wg.Wait()
fmt.Println("All services have exited")
}
在上述代码中:
context.WithCancel
创建了一个可取消的上下文ctx
和取消函数cancel
。downstreamService
函数模拟下游服务调用,通过select
语句监听ctx.Done()
通道,一旦接收到取消信号,就退出循环并结束函数。- 在
main
函数中,启动了多个子协程调用downstreamService
,并在 3 秒后模拟接收到外部取消信号,调用cancel
函数取消上下文,最终等待所有子协程结束。