轮询分配(单机版)

文章介绍了一个在创建监控告警时将服务台人员通过轮询方式平均分配到告警群中的方法。使用了内存中的ConcurrentHashMap来存储和更新用户计数,并设置缓存有效期以确保数据准确性。此外,代码中包含了异常处理和日志记录。此方案适用于单机环境,但提到可以扩展至分布式集群环境。
摘要由CSDN通过智能技术生成

背景

公司新接入一个监控告警需求,在创建监控告警报事时,需要将在线的服务台的人员选取一位加入到新生成的监控告警群中。

解决思路

服务台人员列表使用轮询的方式(基于内存进行实现)平均分配报事

具体解决方案

@Slf4j
public class PollUtil {
/**
     * 缓存有效时间
     */
    private static long CACHE_VALID_TIME = 0;

    private static Lock lock = new ReentrantLock();

    /**
     * 服务台用户统计量
     */
    private static ConcurrentHashMap<String,Integer> userCount = new ConcurrentHashMap<>(16);

    /**
     * 指定服务用户id(轮询方式)
     *
     * @param userIdsByassignment 用户id byassignment
     * @param cacheFailureHours   缓存失效时间
     * @return {@link String}
     */
    public static String designateServiceUserId( Set<String> userIdsByassignment,Integer cacheFailureHours) {
            try {
                lock.lock();
                // 清除缓存信息
                clearCache(cacheFailureHours);
                // 获取轮询信息
                return getMinServiceUserId(userIdsByassignment);
            } catch (Exception e) {
                log.error("初始化MAP出现异常",e);
            } finally {
                lock.unlock();
            }
        return null;
    }

    /**
     * 清除缓存,防止数据误差,指定一个时间段,清理一下缓存数据
     *
     * @param cacheFailureHours 缓存失效时间(单位小时)
     */
    private static void clearCache(Integer cacheFailureHours) {
        log.info("当前过期时间为:{}",CACHE_VALID_TIME);
        log.info("当前时间为:{}",System.currentTimeMillis());
        if (System.currentTimeMillis()>CACHE_VALID_TIME){
            log.info("初始化内容中的人员数据表");
            userCount.clear();
            CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*cacheFailureHours;
        }
    }

    /**
     * 得到最小服务用户id
     *
     * @param userIdsByassignment 用户id byassignment
     * @return {@link String}
     */
    private static String getMinServiceUserId(Set<String> userIdsByassignment) {
        List<String> userList = new ArrayList<>(userIdsByassignment);
        Collections.shuffle(userList);
        // 1. 初始化未初始化到Map的用户列表
        initUserCountMap(userList);
        // 2. 获取Map中的最小值
        String userId = getMinServiceUserId(userList);
        log.info("获取到服务台在线人员OA为:{}", userId);
        return userId;
    }

    /**
     * 初始化用户统计图
     *
     * @param userList 用户列表
     */
    private static void initUserCountMap(List<String> userList) {
        log.info("userCount:{}",JSON.toJSONString(userCount));
        for (String user : userList) {
            try {
                if (StringUtils.isEmpty(user)){
                    continue;
                }
                // 增加人员信息
                if (userCount.containsKey(user)){
                    continue;
                }
                userCount.put(user, Objects.isNull(userCount.get(user)) ? 0 : userCount.get(user) + 1);
            }catch (Exception e){
                log.error("初始化到Map中出现异常",e);
            }
        }
        log.info("userCount:{}",JSON.toJSONString(userCount));
    }

    /**
     * 得到最小服务用户id
     *
     * @param userList 用户列表
     * @return {@link String}
     */
    private static String getMinServiceUserId(List<String> userList) {
        String userId = null;
        try {
            //lock.lock();
            List<Map.Entry<String, Integer>> mapList = new ArrayList(userCount.entrySet());
            Collections.sort(mapList, (Comparator.comparingInt(Map.Entry::getValue)));
            log.info("排序之后的Map集合为:{}", JSON.toJSONString(mapList));
            // 查询当前Map中的用户是否在线
            for (Map.Entry<String, Integer> map : mapList) {
                if (userList.contains(map.getKey())) {
                    log.info("服务台同事:{}在线,选定该OA", map.getKey());
                    userCount.put(map.getKey(), userCount.get(map.getKey()) == null ? 0 : userCount.get(map.getKey()) + 1);
                    userId = map.getKey();
                    // 跳出循环
                    break;
                }
            }
        }catch (Exception e){
            log.error("获取服务台在线人员OA出现异常",e);
        }finally {
            //lock.unlock();
        }
        return userId;
    }
}

总结

此次是基于内存的单机版的轮询方式,还可以用很多方式实现更加适合分布式集群的轮询。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值