钉钉机器人限频

1,348 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

钉钉机器人调用频率限制

我们在开发中往往有很多时候需要对一个特别重要的内容做一个群消息通告,对于办公场景我们可以选择钉钉群机器人,有使用经历的大佬往往都知道,”钉钉的机器人有时候发着发着告警的过一会就不发了,然后过一会又好了“。这个其实就是钉钉机器人的 【调用频率限制】,下面是具体的规则

钉钉机器人【调用频率限制】规则如下:

其实官方也给出了提醒,就是我们要控制提醒频率。

解决方案

解决思路:

对于高频率提醒我们直接提醒摘要信息,举个例子:

N 条消息,我们需要提醒 N 次。如下所示:

1. 用户: 00000001 成功领取 10 元优惠券
2. 用户: 00000002 成功领取 10 元优惠券
N. 用户: 0000000N 成功领取 10 元优惠券

我们进行 2s 提醒一次: 用户 00000001、00000002等 N个用户领取 10 元优惠券成功.

说一下思路:钉钉主要是限制访问频率,我们可以先将每次的消息暂存到一个 Queue 中,通过延迟任务线程池(ScheduledExecutorService) 去定期读取。 如果需要提醒,我们就直接 successMessageQueue.put(message)暂存起来消息,然后通过 Schedule线程池两秒读取消息内容提醒一次,如果具体需要关注详细信息,那么我们可以去查询日志,或者将成功的数据存入库表中。

具体代码

原来的处理代码:

private void dingTalkNoti(String message) {
    dingTalk.sendMsg("成功提醒", message);
}

具体的解决代码:

// 队列长度
private static LinkedBlockingDeque<String> successMessageQueue = new LinkedBlockingDeque<>(20000);
// 延迟任务线程池
private static ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder()
        .setNameFormat("succ-noti-schedule-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy());
static {
    // 执行逻辑
    scheduledExecutor.scheduleAtFixedRate(() -> {
        try {
            // 每次拉取数据最大阈值 
            int maxLen = 5000, i = 0;
            List<String> successMessageList = new ArrayList<>(maxLen);
            while (i < maxLen) {
                String message = successMessageQueue.poll();
                if (message == null) {
                    break;
                }
                successMessageList.add(message);
                i++;
            }
            if (CollectionUtils.isEmpty(successMessageList)) {
                return;
            }

            String messageStr = successMessageList.stream().limit(10)
                    .collect(Collectors.joining(",", "[", "]"));
            if (successMessageList.size() > 10) {
                messageStr = messageStr + " 等";
            	logger.info("处理成功 用户 : {}",  successMessageList.stream().collect(Collectors.joining(",", "[", "]")));    
            }
            dingTalkNoti("处理成功(用户" + successMessageList.size() + "个)", String.format("用户:%s, 处理成功", messageStr));

        } catch (Throwable t) {
            logger.info(" scheduledExecutor error", t);
        }
    }, 0, 2, TimeUnit.SECONDS);
}

总结:其实规避接口限频的本质就是通过数据压缩,可以是内容上,也可以是时间上的;模糊化具体的细节,但是我们可以精准的提醒业务数值,化繁为简。

参考资料: