轮训机制实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | @Service public class BscanCPayPollingHandler { private static final Logger LOGGER = LoggerFactory.getLogger(BscanCPayPollingHandler. class ); /** * 线程池 */ private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 10 , 30 , 5 , TimeUnit.SECONDS, new ArrayBlockingQueue<>( 1000 ), new ThreadPoolExecutor.DiscardPolicy()); @Resource (name = "channelPaymentQueryServiceImpl" ) private IChannelPaymentQueryService channelPaymentQueryService; @Inject private IRefundForTradeService refundForTradeService; /** * 查询订单状态,每5s一次 * * @param requestContext 请求上下文 * @param times 时间 */ public void doQuery(RequestContext<ChannelPosPaymentRequest> requestContext, int times) { // 1.动态调整线程池情况 checkThreadPool(); // 2.执行轮询业务 threadPoolExecutor.execute( new BscanCPayQueryThread(times, requestContext, channelPaymentQueryService, refundForTradeService)); // 3.动态调整线程池情况 checkThreadPool(); } /** * 动态调整线程池大小 */ public void checkThreadPool() { int activeCount = threadPoolExecutor.getActiveCount(); int corePoolSize = threadPoolExecutor.getCorePoolSize(); int maximumPoolSize = threadPoolExecutor.getMaximumPoolSize(); int usedSize = threadPoolExecutor.getQueue().size(); LOGGER.info( "Number of thread pool active threads responsible for polling" , activeCount, "number of core threads" , corePoolSize, "maximum number of threads" , maximumPoolSize, "Number of queue tasks" , usedSize); if ((activeCount > corePoolSize - 5 ) && (corePoolSize + 5 < maximumPoolSize)) { threadPoolExecutor.setCorePoolSize(corePoolSize + 5 ); LOGGER.info( "The number of core threads in the thread pool responsible for polling is expanded by 10" ); } if (activeCount < corePoolSize - 10 ) { threadPoolExecutor.setCorePoolSize(corePoolSize - 5 ); LOGGER.info( "The number of core threads responsible for polling in the thread pool is reduced by 10" ); } } } |
/** * 轮询支付结果异步线程:无异步通知 * * @author DDD * @Since 2022/5/13 */ public class BscanCPayQueryThread implements Runnable { /** * 日志 */ private static final Logger LOGGER = LoggerFactory.getLogger(BscanCPayQueryThread.class); /** * 退款服务端 */ private static final String REFUND_SOURCE_IPS = "DDD"; /** * 异步调用工作查询支付结果线程 */ private static final String LOG_PREFIX = "【异步调用查询工作线程】"; private final int times; private final RequestContext<ChannelPosPaymentRequest> requestContext; private final IChannelPaymentQueryService channelPaymentQueryService; private final IRefundForTradeService refundForTradeService; public BscanCPayQueryThread(int times, RequestContext<ChannelPosPaymentRequest> requestContext, IChannelPaymentQueryService channelPaymentQueryService, IRefundForTradeService refundForTradeService) { this.times = times; this.requestContext = requestContext; this.channelPaymentQueryService = channelPaymentQueryService; this.refundForTradeService = refundForTradeService; } @Override public void run() { String tempMsg = "**************启动工作支付结果查询线程******************"; try { LOGGER.info(LOG_PREFIX, tempMsg); pollingOrder(requestContext, times); tempMsg = " ****************工作支付结果查询线程结束*******************"; LOGGER.info(LOG_PREFIX, tempMsg); } catch (Exception exception) { tempMsg = LOG_PREFIX + " 运行出现异常:" + exception.getLocalizedMessage(); LOGGER.error(tempMsg, exception); } } private void pollingOrder(RequestContext<ChannelPosPaymentRequest> requestContext, int times) { String tempMsg = ""; // 1.参数校验 if (times <= 0) { times = 1; } DelayQueue<OrderDelayed> orderDelayedDelayQueue = new DelayQueue<>(); if (null == requestContext || StringUtils.isEmpty(requestContext.getChannelNo())) { tempMsg = "渠道号为空,工作支付结果异步查询触发失败,错误码:"; LOGGER.error(tempMsg, PayErrorCodeEnum.CHANNEL_QUERY_FAIL.getCode()); throw new ChannelException(PayErrorCodeEnum.CHANNEL_QUERY_FAIL.getCode(), "渠道号为空,工作支付结果异步查询触发失败"); } // 2.初始化延时队列 for (int i = 0; i < times; i++) { orderDelayedDelayQueue.put(new OrderDelayed(5 * (i + 1), requestContext.getChannelNo(), TimeUnit.SECONDS)); } // 3. 触发查询 int queueSize = orderDelayedDelayQueue.size(); try { for (int i = 0; i < queueSize; i++) { LOGGER.info("The execution channel serial number is {} the time is {}", requestContext.getChannelNo(), String.valueOf(i + 1)); OrderDelayed orderDelayed = orderDelayedDelayQueue.take(); ChannelPaymentQueryRequest channelPaymentQueryRequest = new ChannelPaymentQueryRequest(); channelPaymentQueryRequest.setRequestModule(SYSTEM_CODE.getValue()); channelPaymentQueryRequest.setChannelNo(orderDelayed.getOrderId()); channelPaymentQueryRequest.setPayQueryType(PayQueryType.TRADE_QUERY.getCode()); MessageResponse<ChannelPaymentQueryResponse> channelResponse = channelPaymentQueryService.queryTrade(channelPaymentQueryRequest); LOGGER.info("queryChannel response ", channelResponse); if (channelResponse.isSuccessful()) { BankTransStatusEnum status = BankTransStatusEnum.getEnum(channelResponse.getResultData().getPayStatus()); // 判断工作支付,是否是最终状态,支付失败或支付成功 if (anyPayStatusMatch(status.getCode(), SUCCESS, FAIL, REFUND, FINISH, CLOSE)) { LOGGER.info("Order payment status is", status.getCode()); break; } } // 4.最后一次查询结束后,仍未获得订单结果,撤销订单 if (i == (queueSize - 1)) { LOGGER.info("To cancel the payment order, the channelNo is ", requestContext.getChannelNo()); cancelOrder(requestContext); } } } catch (InterruptedException e) { LOGGER.info("The thread of getting the payment order result is abnormal, and the order is cancelled ", requestContext.getChannelNo()); cancelOrder(requestContext); tempMsg = "获取订单支付结果线程异常中断.已撤销订单:"; LOGGER.error(tempMsg, e); throw new ChannelException(PayErrorCodeEnum.CHANNEL_QUERY_FAIL.getCode(), tempMsg + e.getLocalizedMessage(), e); } } private boolean cancelOrder(RequestContext<ChannelPosPaymentRequest> requestContext) { String tempMsg = "**************cancel start*****************"; LOGGER.info(LOG_PREFIX, tempMsg); RefundTradeRequest refundTradeRequest = new RefundTradeRequest(); ChannelPaymentTradeVo tradeVo = requestContext.getDataPo(); refundTradeRequest.setMerchantNo(tradeVo.getMerchantNo()); refundTradeRequest.setOutTradeNo(tradeVo.getOutTradeNo()); refundTradeRequest.setOriOutTradeNo(tradeVo.getOutTradeNo()); refundTradeRequest.setRequestModule(SYSTEM_CODE.getValue()); refundTradeRequest.setChannelCode(requestContext.getChannelCode()); refundTradeRequest.setBankTradeNo(tradeVo.getBankTradeNo()); refundTradeRequest.setBankCode(requestContext.getBankCode()); refundTradeRequest.setOriTradeNo(requestContext.getTradeNo()); refundTradeRequest.setRefundSource(REFUND_SOURCE_IPS); refundTradeRequest.setPosCancel(true); String currencyCode = tradeVo.getCurrency(); CurrencyEnum currencyEnum = CurrencyEnum.getEnum(currencyCode); if (null == currencyEnum) { throw new ChannelRefundException(PayErrorCodeEnum.CHANNEL_REFUND_FAIL.getCode(), "获取币种(currencyEnum)为空"); } String amount = null; if (null != tradeVo.getAmount()) { amount = String.valueOf(tradeVo.getAmount()); } BigDecimal transformData = BigDecimal.valueOf(parseDouble(amount + "")) .divide(new BigDecimal(10).pow(currencyEnum.getSeparator())) .setScale(currencyEnum.getSeparator()); Money refundMoney = new Money(currencyEnum.getCode(), transformData.toString()); refundTradeRequest.setRefundMoney(refundMoney); tempMsg = "user did not pay,cancel the order start! "; LOGGER.info(tempMsg, JSON.toJSONString(refundTradeRequest)); MessageResponse<CancelTradeResponseData> response = refundForTradeService.cancel(refundTradeRequest); tempMsg = "user did not pay,cancel the order end!"; LOGGER.info(tempMsg, JSON.toJSONString(response)); tempMsg = "**************cancel end*****************"; LOGGER.info(LOG_PREFIX, tempMsg); return response.isSuccessful(); } /** * 判断渠道成功状态 * * @param payStatus 支付状态 * @param bankTransStatusEnum 银行支付状态枚举 * @return 成功状态 */ public static boolean anyPayStatusMatch(String payStatus, BankTransStatusEnum... bankTransStatusEnum) { return Arrays.stream(bankTransStatusEnum).anyMatch(status -> status.getCode().equals(payStatus)); } class OrderDelayed implements Delayed { private long time; private String orderId; public OrderDelayed(long time, String orderNo, TimeUnit unit) { this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0); this.orderId = orderNo; } @Override public long getDelay(TimeUnit unit) { return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed delayed) { OrderDelayed orderDelayed = (OrderDelayed) delayed; long diff = this.time - orderDelayed.time; if (diff <= 0) { return -1; } else { return 1; } } public String getOrderId() { return orderId; } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)