面试题答案
一键面试设计思路
- 全局Context传递:在整个微服务链式调用的入口处创建一个
Context
,并将其传递给每一个下游服务。这个Context
可以是WithCancel
、WithTimeout
或者WithDeadline
创建的,以便实现取消或超时功能。 - 子任务并发管理:对于每个服务内的多个并发子任务,将接收到的
Context
传递给每个子任务。每个子任务在执行过程中,需要定期检查Context
的状态,一旦发现Context
被取消或超时,立即停止执行。 - 传播取消信号:当某个服务接收到取消信号(通过
Context
),它不仅要停止自身的子任务,还要将取消信号传递给下游服务,以确保整个调用链的一致性取消。
关键代码片段(以Go语言为例)
创建和传递Context
package main
import (
"context"
"fmt"
"time"
)
// 模拟下游服务
func downstreamService(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(2 * time.Second):
fmt.Println("Downstream service completed")
return nil
}
}
// 模拟上游服务,包含并发子任务
func upstreamService(ctx context.Context) error {
var errChan = make(chan error, 2)
// 子任务1
go func() {
select {
case <-ctx.Done():
errChan <- ctx.Err()
return
case <-time.After(3 * time.Second):
fmt.Println("Sub - task 1 completed")
errChan <- nil
}
}()
// 子任务2
go func() {
select {
case <-ctx.Done():
errChan <- ctx.Err()
return
case <-time.After(1 * time.Second):
fmt.Println("Sub - task 2 completed")
errChan <- nil
}
}()
for i := 0; i < 2; i++ {
err := <-errChan
if err != nil {
return err
}
}
// 调用下游服务
return downstreamService(ctx)
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
err := upstreamService(ctx)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}
在上述代码中:
main
函数创建了一个带超时的Context
并传递给upstreamService
。upstreamService
内部启动了两个并发子任务,每个子任务都监听Context
的取消信号。同时,upstreamService
还调用了下游服务downstreamService
并传递Context
。downstreamService
同样监听Context
的取消信号,以确保在超时或取消时能够正确响应。