前言
这两天面试了一个物联网公司高级研发,面试题是下面这样子
公司领导,部门主管,小组组长,组成员4级,假如有个 疫情预警,先通知组人员(对个人,主要有一个处理就算处理了) 如果3分钟没处理,就往组长发短信,如果组长3分钟没处理就往上级推送。一级一级的。 要求单程序并发至少支持1000tps预警事件
说实话上面需求在我做的过往项目里有过类似需求,我也只是依稀记得自己是怎么做的。类似于使用第三方任务调度框架完成上面的3分钟超时处理,然后至于分级发送则更简单了,再不济就是使用if、else这样的最原始验证即可。但是这样的题目丢到面试题上我是一下就不知所措了。自然最终的结果也不尽人意(我最终提交的代码就是采用一个事件总线实现报警的推送,但是并未对其进行超时分级发送) 这个自然是错误的,我其实当时也想过使用Timer,但是内心对Timer就是感觉用性能做代价去换取最终的结果。
解析需求
过了几天还是觉得要手纯撸代码将上面功能撸出来,不然如何成长呢!
拆分下需求可以得到的消息是有一个事件。这个事件就是报警事件,通过报警事件需要将消息推送给不同职位的工作人员,而且必须遵循岗位从下至上,但凡人员收到报警消息则表示报警通知已完成,其次就是有一个三分钟需要处理。
通过上面的需求分析可以知道我们必须要定义一个枚举,记录职称高低。
/// <summary> /// 工作级别 /// </summary> public enum JobLevel : int { 公司领导 = 1, 部门主管 = 2, 小组组长 = 3, 组成员 = 4 }
其次我们至少存在两个类,一个是产生报警的对象,这个对象有需要通知的报警信息和报警信息发送结果,当然更加少不了我们订阅了报警消息的订阅者。这里想了下,可以采用观察者设计模式进行解耦。
/// <summary> /// 发布者接口 /// </summary> public interface IPublish { /// <summary> /// 新增订阅者(观察者) /// </summary> /// <param name="subscriber"></param> void AddSubscriber(SubscriberPeopleBase subscriber); /// <summary> /// 移除订阅者(观察者) /// </summary> /// <param name="subscriber"></param> void RemoveSubscriber(SubscriberPeopleBase subscriber); /// <summary> /// 发送报警消息 /// </summary> void SendNotify(); /// <summary> /// 出现警报 /// </summary> /// <param name="msg">警报消息</param> void CreateJB<p>本文来源gao!daima.com搞$代!码#网#</p>(string msg);
接下来就是实现上面接口了!
/// <summary> /// 报警发布者 /// </summary> public class Baojing : IPublish { /// <summary> /// 订阅者集合 /// </summary> public List<SubscriberPeopleBase> SubscriberLst { get; set; } /// <summary> /// 报警消息 /// </summary> public string Msg { get; set; } /// <summary> /// 有无接收成功 /// </summary> public bool IsSucess { get; set; } /// <summary> /// 消息通知计数器 /// </summary> public Timer NotifyTimer { get; set; } /// <summary> /// 记录当前发送消息的岗位 /// </summary> public JobLevel CurrentJobLevel = JobLevel.组成员; public void AddSubscriber(SubscriberPeopleBase subscriber) { if (SubscriberLst == null) SubscriberLst = new List<SubscriberPeopleBase>(); SubscriberLst.Add(subscriber); } public void CreateJB(string msg) { Msg = msg; } public void RemoveSubscriber(SubscriberPeopleBase subscriber) { if (SubscriberLst != null) SubscriberLst.Remove(subscriber); } /// <summary> /// 发送报警消息 /// </summary> public void SendNotify() { if (SubscriberLst?.Count > 0) { //循环从职位低到高 SubscriberLst.OrderByDescending(p => (int)p.Title); //立即执行CheckNotifySendResult,以为3秒为间隔 NotifyTimer = new Timer(CheckNotifySendResult, null, 0, 3000); } } public void CheckNotifySendResult(object stat) { //先要停止定时器,防止并发 NotifyTimer.Change(-1, 3000); //第一次发给职位最小 枚举最大的组成员 SubscriberPeopleBase subscriberPeople = SubscriberLst.Find(p => (((int)CurrentJobLevel + 1) - (int)p.Title) == 1); if (subscriberPeople == null) return; //已经是最小的 if (!IsSucess) { IsSucess = subscriberPeople.ReceiveData(this); if (!IsSucess) { CurrentJobLevel = CurrentJobLevel!= JobLevel.公司领导?(JobLevel)((int)CurrentJobLevel) - 1: JobLevel.公司领导; NotifyTimer.Change(3000, 3000); } } else { Console.WriteLine($"停止计数器 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); NotifyTimer.Dispose(); } } }