微信公众号后台回复5s重试解决方案和思路

目录

前置条件

1.微信公众号申请

2.内网穿透

场景

解决思路

1.客服回复

2.第一次提问后使用异步线程,然后再次提问获得回答

3.在三次重试中,获取返回,用户只需要提问一次

限制


前置条件

1.微信公众号申请

        我们在上网冲浪的时候,去申请一些资源的时候,关注某个微信公众号,发送一串数字就会给一个解锁密码以供后续操作,这个环节需要配合 申请微信公众号。具体的微信公众号的申请请看微信公众号平台教程或者其他总结,在这里不多做赘述。

2.内网穿透

        之所以会使用到内网穿透,是因为在配置微信公众号服务器的时候,需要公网的地址,如果你的服务器部署在自己电脑上的话,那么实际上微信公众号是访问不到你的机器的。所以也就是需要将你自己的服务器和公网进行一个应该,在这里推荐 NATAPP这个网站,可以使用免费的,也可以使用付费的,但是付费的还需要额外花几块钱买一个二级域名。

场景

        近期我遇到了这么一个场景,我想将chatgpt的能力 和 微信公众号绑定,其实也就是我向一个微信公众号发送问题,那么 后台就会返回我chatgpt的答案,这样,就不需要翻墙,很方便,也是扩展chatgpt的使用场景了。

        但是当真正开发完成的时候,发现,微信公众号有一个超时时间5s,也就是如果5s内没有回复就要重试请求,一共三次,如果三次都没有返回请求的话,那么 就会提示 微信公众号不可用。

        而通过实践,chatgpt很大概率上不能在5s内完成回复。那么就没办法做到智能问答的效果。

解决思路

1.客服回复

        通过查阅各种各样的资料,这个办法一直是大家广泛提起的,其实就是 使用客服回答 接口进行回答即可。但是我们所注册的微信公众号更多的都是个人微信公众号,没办法进行微信认证,所以不能使用客服接口,所以该方法可能对普通人不适用。

2.第一次提问后使用异步线程,然后再次提问获得回答

        这个解决思路其实还挺简单的,原理也很简单,就是当发第一次请求的时候,内部启动一个异步线程先回复一个消息 :“请稍等几秒钟再次回复【原来的消息】”,将这个消息存储进一个map中,然后等待异步线程执行结束,将map存储的key中的value补充上,等到下次再次提问的时候,就直接从key里的value取即可。

3.在三次重试中,获取返回,用户只需要提问一次

         本质上其实是一个具有超时重试机制的任务处理功能,具体看代码。

public class CallableCallback {

    private static final Logger logger = LoggerFactory.getLogger(CallableCallback.class);
    public static final ConcurrentHashMap<Long, Future<String>> map = new ConcurrentHashMap<>();
    public static final AtomicInteger atomicCount = new AtomicInteger();
    // GPT 任务线程池
    public static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
            10, 10,
            3, TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(100), (runnable) -> new Thread(runnable, atomicCount.getAndAdd(1) + "号线程"),
            new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws InterruptedException {
        Long tid = 1L;
        new Thread(new MyTask(tid, "请求A"), "请求A").start();
        Thread.sleep(5000);
        new Thread(new MyTask(tid, "重试A1"), "重试A1").start();
        Thread.sleep(5000);
        new Thread(new MyTask(tid, "重试A2"), "重试A2").start();
        Thread.sleep(5000);

        executor.shutdown();
    }

    static class MyTask implements Runnable {

        private Long tid;
        private String name;
        /**
         * GPT 请求耗时
         */
        private Long gptTime;
        private TimeUnit gptTimeUnit;
        /**
         * 接口超时
         */
        private final Long outTime = 4800L;
        private final TimeUnit outTimeUnit = TimeUnit.MILLISECONDS;

        public MyTask(Long tid, String name) {
            this.tid = tid;
            this.name = name;
            this.gptTime = 12L;
            this.gptTimeUnit = TimeUnit.SECONDS;
        }

        public MyTask(Long tid, String name, Long gptTime, TimeUnit gptTimeUnit) {
            this.tid = tid;
            this.name = name;
            this.gptTime = gptTime;
            this.gptTimeUnit = gptTimeUnit;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            Future<String> future = map.get(tid);
            String res;
            if (future == null) {
                // 模拟 GPT 耗时接口
                logger.info("<-----线程:{} 开始执行完gpt任务----->", name);
                future = executor.submit(() -> testGpt(gptTime, gptTimeUnit));
                try {
                    res = future.get(outTime, outTimeUnit);
                    long end = System.currentTimeMillis();
                    logger.info("线程:{} 执行完gpt任务,任务成功返回,耗时:{} 毫秒,结果:{}", name, end - start, res);
                } catch (InterruptedException | ExecutionException e) {
                } catch (TimeoutException e) {
                    logger.info("线程:{} 执行完gpt任务,耗时5秒,任务超时", name);
                    // TODO 超时了,任务添加到map,直接返回,不管了,让后面的请求重试
                    map.put(tid, future);
                }
                return;
            }
            // 这是重试请求,直接从 Future 获取第一次请求的结果
            try {
                logger.info("线程:{} 开始尝试从 Future 获取第一次请求的结果,任务结果", name);
                res = future.get(outTime, outTimeUnit);
                logger.info("线程:{} 在规定时间内从 Future 获取第一次请求的结果:{}", name, res);
                // 移除阻塞队列
                map.remove(tid);
            } catch (InterruptedException | ExecutionException e) {
            } catch (TimeoutException e) {
                // 获取失败
                logger.info("线程:{} 获取第一次请求的结果,超时", name);
            }
        }

        /**
         * 模拟Gpt接口,耗时指定时间
         */
        private String testGpt(final long time, final TimeUnit timeUnit) {
            try {
                timeUnit.sleep(time);
            } catch (InterruptedException e) {
            }
            return "gpt接口返回";
        }
    }

}

限制

        其实主要是针对第二种 和 第三种方法的限制的,一般来说 chatgpt接口都能在 15s内返回,或者其他任务也是一样的,如果能保证返回,那么就可以使用第三种办法,如果不能保证,还是乖乖使用第二种办法来解决问题。

  • 24
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ASP微信公众号自动回复是指通过ASP编程语言实现的一种功能,当用户在微信公众号中发送消息时,公众号会根据预设的规则和条件自动回复相应的内容。 通过ASP微信公众号自动回复,可以实现以下功能: 1. 关键词回复:根据用户发送的关键词,自动回复相应的内容。可以预设一系列常见问题的关键词,当用户发送匹配的关键词时,公众号会自动回复相应的答案。 2. 模糊匹配:可以设置关键词的模糊匹配规则,即使用户输入了略有不同的关键词,公众号也可以根据相似度自动回复相应的答案。 3. 自定义回复:用户可以根据实际需求自定义回复的内容,包括文本、图片、语音等形式。可以根据用户的消息类型进行不同的回复,提供更丰富的交互体验。 4. 多场景回复:可以根据用户所在的场景进行不同的回复。例如,当用户在购物场景中发送消息时,公众号可以自动回复商品信息和优惠信息;当用户在咨询场景中发送消息时,公众号可以自动回复相关问题的答案。 5. 定时回复:可以设置定时任务,根据预设的时间进行自动回复。例如,可以设置每天早上9点自动回复早安,晚上10点自动回复晚安。 通过ASP微信公众号自动回复,可以提高公众号的效率和服务质量,实现自动化的客户互动。同时,也可以节省人力资源,让公众号能够更好地应对大量用户的咨询和需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃芝士的土豆倪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值