《通过C#学Proto.Actor模型》之Supervision
Supervision,字面意思是监督,是父Actor发现子Actor有异常发生后,对子Actor产用保种策略处理的机制,如果父Actor不处理,则往上传递。
子Actor发生异常后处理的策略有:
Resume:立即恢复
Restart:恢复之前停止Actor并重新创建它
Stop:停止
Escalate:上报到父级
Supervisor的通过Props.WithChildSupervisorStarategy()来实施的,这个方法第一个参数是接收异常和Actor的PID,以便按一定方式处理异常,第二个参数是重启的次数,第三个参数是两次重启的间隔(按照官方文档,两个连续重启时间大于间隔时间,次数会复位,但实则只按次数走,间隔不起作用)达到最大次数据,子Actor将重新生成。
码友看代码:
1 using Proto; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Threading.Tasks; 6 7 namespace P006_Supervision 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 //设置监督策略,指向SupervisiorMode方法,重启次数为3,两次之间间隔1s 14 var props = Actor.FromProducer(() => new ShopingCatActor()).WithChildSupervisorStrategy(new OneForOneStrategy(SupervisorMode.Decide, 3, TimeSpan.FromSeconds(1))); 15 var pid = Actor.Spawn(props); 16 var user = new User { UserName = "gsw" }; 17 18 var sn = 1; 19 while (true) 20 { 21 Console.WriteLine($"{sn++}--------------------begin-----------------"); 22 foreach (var goods in user.ShopingCat.Goodses) 23 { 24 Console.WriteLine(goods); 25 } 26 Console.WriteLine("---------------------end------------------"); 27 Console.ReadLine(); 28 pid.Request(user, pid); 29 } 30 } 31 } 32 /// <summary> 33 /// Supervisor 模式 34 /// </summary> 35 class SupervisorMode 36 { 37 /// <summary> 38 /// 用来处理异常发生的后续操作 39 /// </summary> 40 /// <param name="pid">PID</param> 41 /// <param name="reason">异常原因,Exception类型</param> 42 /// <returns></returns> 43 public static SupervisorDirective Decide(PID pid, Exception reason) 44 { 45 Console.WriteLine(" 异常发生:" + reason.Message + " " + pid); 46 switch (reason) 47 { 48 //重新开始的异常 49 case RecoverableException _: 50 return SupervisorDirective.Restart; 51 //停止异常 52 case FatalException _: 53 return SupervisorDirective.Stop; 54 //其他都上报 55 default: 56 return SupervisorDirective.Escalate; 57 } 58 } 59 } 60 /// <summary> 61 /// 购物车actor 62 /// </summary> 63 class ShopingCatActor : IActor 64 { 65 ShopingCat _shopingCat; 66 public ShopingCatActor() 67 { 68 _shopingCat = new ShopingCat(); 69 Console.WriteLine("*******************actor ShopingCatActor************************"); 70 } 71 public Task ReceiveAsync(IContext context) 72 { 73 PID childPid; 74 if (context.Children == null || context.Children.Count == 0) 75 { 76 var props = Actor.FromProducer(() => new GoodsActor()); 77 childPid = context.Spawn(props); 78 } 79 else 80 { 81 childPid = context.Children.First(); 82 } 83 switch (context.Message) 84 { 85 case User user: 86 childPid.Request(_shopingCat, childPid); 87 user.ShopingCat = _shopingCat; 88 break; 89 } 90 return Actor.Done; 91 } 92 } 93 /// <summary> 94 /// 商品actor 95 /// </summary> 96 class GoodsActor : IActor 97 { 98 public Task ReceiveAsync(IContext context) 99 { 100 switch (context.Message) 101 { 102 case ShopingCat shopingCat: 103 104 var goods = new Goods { Name = "红茶", Price = 3.0m, Describe = "统一" }; 105 //用来随机产生异常 106 var random = new Random(); 107 goods.Quantity = random.Next(1, 3) - 1; 108 if (goods.Quantity <= 0) 109 { 110 throw new RecoverableException("数量不能小于等于0"); 111 } 112 else 113 { 114 shopingCat.Goodses.Add(goods); 115 Console.WriteLine($"添加 {goods} 到购物车里"); 116 } 117 break; 118 } 119 return Actor.Done; 120 } 121 } 122 /// <summary> 123 /// 用户 124 /// </summary> 125 class User 126 { 127 public ShopingCat ShopingCat { get; set; } = new ShopingCat(); 128 public string UserName { get; set; } 129 } 130 /// <summary> 131 /// 购物车 132 /// </summary> 133 class ShopingCat 134 { 135 public List<Goods> Goodses 136 { get; set; } = new List<Goods>(); 137 } 138 /// <summary> 139 /// 商品 140 /// </summary> 141 class Goods 142 { 143 public string Name { get; set; } 144 145 public int Quantity { get; set; } 146 147 public decimal Price { get; set; } 148 149 public string Describe { get; set; } 150 public override string ToString() 151 { 152 return $"Name={Name},Quantity={Quantity},Price={Price},Describe={Describe}"; 153 } 154 } 155 156 }
Demo中有三个实体类,用户类,购物车类,商品类,他们的关系一目了解,聚合关系。有两个Actor,购物车Actor(ShopingCatActor),商品Actor(GoodsActor),商品Actor是购物车Actor子Actor;ShopingCatActor下有监督策略,在
SupervisorMode下的Decide方法中,处理不同的异常,采用不同的Actor策略。GoodsActor中,添加商品时根据数量来决定是否产生异常。
看运行结果:
注意看ID $1/$2,是在发生四次异常后才生成$1/$3的(这个与文档说法有出入,也许是我理解有问题,是重启3次,不是启动3次)
****欢迎关注我的asp.net core系统课程****
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524