主流程图
开始
↓
检查是否有队列缓存
↓ (有缓存)
询问消费者序列令牌
↓
消费者返回令牌?
↓ (是)
根据令牌创建游标
↓
游标.MoveNext() (移动到下一个消息)
↓
保存 LastToken
↓
握手成功
↓
开始消息投递
↓
结束
↓ (否)
使用缓存令牌创建游标
↓
保存 LastToken = null
↓
握手成功
↓
开始消息投递
↓
结束
异常处理流程图
询问消费者令牌时发生异常
↓
检查代理是否正在关闭
↓ (是)
返回 false (停止处理)
↓
结束
↓ (否)
调用错误协议处理异常
↓
订阅被标记为故障?
↓ (是)
返回 false (停止处理该消费者)
↓
结束
↓ (否)
尝试使用缓存令牌创建游标
↓
成功?
↓ (是)
握手完成
↓
结束
↓ (否)
使用 null 令牌创建游标 (从头开始)
↓
握手完成
↓
结束
重试机制流程图
开始重试
↓
调用消费者.GetSequenceToken()
↓
成功?
↓ (是)
返回结果
↓
结束
↓ (否)
检查重试条件
↓
满足重试条件?
↓ (是)
等待退避时间
↓
重试次数 < 最大重试次数?
↓ (是)
重试
↓
回到"调用消费者.GetSequenceToken()"
↓ (否)
抛出异常
↓
结束
↓ (否)
抛出异常
↓
结束
消息投递流程图
握手完成
↓
获取当前消息
↓
投递给消费者
↓
消费者处理成功?
↓ (是)
移动到下一个消息
↓
还有更多消息?
↓ (是)
继续投递
↓
回到"获取当前消息"
↓ (否)
等待新消息或定期握手
↓
结束
↓ (否)
处理消费者错误
↓
标记订阅为故障?
↓ (是)
停止投递
↓
结束
↓ (否)
重试投递
↓
回到"投递给消费者"
关键决策点说明
1. 为什么需要 MoveNext()?
消费者说:"我处理到消息 #100"
↓
代理理解:"消息 #100 已经处理过了"
↓
游标指向消息 #100
↓
MoveNext() 移动到消息 #101
↓
从消息 #101 开始投递
2. 重试条件判断
发生异常
↓
是 ClientNotAvailableException?
↓ (是)
不重试 (客户端不可用,重试无意义)
↓
结束
↓ (否)
代理正在关闭?
↓ (是)
不重试 (系统正在关闭)
↓
结束
↓ (否)
重试 (网络问题等临时性错误)
↓
继续
3. 备用方案选择
握手失败
↓
尝试使用缓存令牌
↓
成功?
↓ (是)
使用缓存位置
↓
结束
↓ (否)
使用 null 令牌 (从头开始)
↓
结束
设计优势总结
- 可靠性:多重容错机制确保消息不丢失
- 一致性:通过令牌机制保证消息顺序
- 性能:按需投递,避免重复处理
- 可扩展性:支持多消费者、多流并发
- 可观测性:完善的日志和监控
这个握手机制是 Orleans 流系统可靠性的核心保障,通过精心设计的流程和异常处理,确保了分布式环境下的消息可靠投递。