123
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
package com.ruoyi.find;
|
||||||
|
|
||||||
|
import com.ruoyi.cai.ws.util.SendMessageI;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SendMessageHttpImpl implements SendMessageI {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String sessionKey, String message){
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ruoyi</groupId>
|
<groupId>com.ruoyi</groupId>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public class AmqpWsProducer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void sendRoomSettleDelay(String message, Integer timeout){
|
public void sendRoomSettleDelay(String message, Integer timeout){
|
||||||
rabbitTemplate.convertAndSend(RoomSettleDelayWsMqConstant.EXCHANGE_NAME,
|
rabbitTemplate.convertAndSend(RoomSettleDelayWsMqConstant.EXCHANGE_NAME,
|
||||||
RoomSettleDelayWsMqConstant.ROUTING_KEY,
|
RoomSettleDelayWsMqConstant.ROUTING_KEY,
|
||||||
|
|||||||
@@ -42,8 +42,14 @@ public class Agora {
|
|||||||
if(jsonobject == null){
|
if(jsonobject == null){
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
JSONArray jsonArray = jsonobject.getJSONObject("data").getJSONArray("broadcasters");
|
JSONObject data = jsonobject.getJSONObject("data");
|
||||||
return jsonArray.toJavaList(String.class);
|
if(data != null){
|
||||||
|
JSONArray jsonArray = data.getJSONArray("broadcasters");
|
||||||
|
if(jsonArray != null){
|
||||||
|
return jsonArray.toJavaList(String.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,13 @@ public class RoomWebSocketHandler extends AbstractWebSocketHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
|
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
|
||||||
log.error("[transport error] sessionId: {} , exception:{}", session.getId(), exception.getMessage());
|
log.error("[transport error] sessionId: {} , exception:{}", session.getId(), exception.getMessage());
|
||||||
|
try{
|
||||||
|
if(session.isOpen()){
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,7 +140,13 @@ public class RoomWebSocketHandler extends AbstractWebSocketHandler {
|
|||||||
// TODO 连接关闭 是否要删除fd的关系
|
// TODO 连接关闭 是否要删除fd的关系
|
||||||
WebSocketSessionHolder.removeSession(session.getId());
|
WebSocketSessionHolder.removeSession(session.getId());
|
||||||
log.info("[disconnect] sessionId: {},token:{}", session.getId(), token);
|
log.info("[disconnect] sessionId: {},token:{}", session.getId(), token);
|
||||||
session.close();
|
try{
|
||||||
|
if(session.isOpen()){
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import lombok.AccessLevel;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -17,19 +18,36 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
public class WebSocketSessionHolder {
|
public class WebSocketSessionHolder {
|
||||||
|
|
||||||
private static final Map<String, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
|
private static final Map<String, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<Long, String> USER_SESSION_ID_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public static int size(){
|
public static int size(){
|
||||||
return USER_SESSION_MAP.size();
|
return USER_SESSION_MAP.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addSession(String sessionKey, WebSocketSession session) {
|
public static void addSession(String sessionKey, WebSocketSession session,Long userId) {
|
||||||
USER_SESSION_MAP.put(sessionKey, session);
|
USER_SESSION_MAP.put(sessionKey, session);
|
||||||
|
if(USER_SESSION_ID_MAP.containsKey(userId)){ // T人动作
|
||||||
|
String sessionKeyOld = USER_SESSION_ID_MAP.get(userId);
|
||||||
|
if(sessionKeyOld != null){
|
||||||
|
WebSocketSession webSocketSession = USER_SESSION_MAP.get(sessionKeyOld);
|
||||||
|
if(webSocketSession != null){
|
||||||
|
if(webSocketSession.isOpen()){
|
||||||
|
try {
|
||||||
|
webSocketSession.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeSession(sessionKeyOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
USER_SESSION_ID_MAP.put(userId,sessionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeSession(String sessionKey) {
|
public static void removeSession(String sessionKey) {
|
||||||
if (USER_SESSION_MAP.containsKey(sessionKey)) {
|
USER_SESSION_MAP.remove(sessionKey);
|
||||||
USER_SESSION_MAP.remove(sessionKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WebSocketSession getSessions(String sessionKey) {
|
public static WebSocketSession getSessions(String sessionKey) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
|
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import org.redisson.api.RedissonClient;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class WebSocketManager {
|
public class WebSocketManager {
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -64,14 +66,21 @@ public class WebSocketManager {
|
|||||||
return room.getRoomId();
|
return room.getRoomId();
|
||||||
}
|
}
|
||||||
RLock lock = redissonClient.getLock(String.format(RedisConstant.INIT_ROOM_LOCK, userCall.getFromUid(), userCall.getToUid()));
|
RLock lock = redissonClient.getLock(String.format(RedisConstant.INIT_ROOM_LOCK, userCall.getFromUid(), userCall.getToUid()));
|
||||||
boolean b = lock.tryLock();
|
boolean b;
|
||||||
if(!b){
|
|
||||||
throw new ServiceException("系统繁忙");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
|
b = lock.tryLock(1, TimeUnit.MINUTES);
|
||||||
|
if(!b){
|
||||||
|
throw new ServiceException("系统繁忙");
|
||||||
|
}
|
||||||
roomId = initRoom(userCall);
|
roomId = initRoom(userCall);
|
||||||
}finally {
|
} catch (InterruptedException e) {
|
||||||
lock.unlock();
|
throw new ServiceException("系统繁忙");
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
lock.unlock();
|
||||||
|
}catch (Exception e){
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return roomId;
|
return roomId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class OpenLogic {
|
|||||||
WsExceptionUtil.throwExceptionFast(session,"无效token");
|
WsExceptionUtil.throwExceptionFast(session,"无效token");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WebSocketSessionHolder.addSession(session.getId(), session);
|
WebSocketSessionHolder.addSession(session.getId(), session, wsToken.getUserId());
|
||||||
Long roomId = wsToken.getRoomId();
|
Long roomId = wsToken.getRoomId();
|
||||||
Long userId = wsToken.getUserId();
|
Long userId = wsToken.getUserId();
|
||||||
Room room = roomService.load(roomId);
|
Room room = roomService.load(roomId);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -99,7 +100,7 @@ public class SettleService {
|
|||||||
/**
|
/**
|
||||||
* 结算处理
|
* 结算处理
|
||||||
*/
|
*/
|
||||||
public SettleResp processOn(Long roomId){
|
public SettleResp processOn(Long roomId) {
|
||||||
Room room = roomService.load(roomId);
|
Room room = roomService.load(roomId);
|
||||||
if(room == null){
|
if(room == null){
|
||||||
log.warn("房间不存在,无需结算 roomId={}",roomId);
|
log.warn("房间不存在,无需结算 roomId={}",roomId);
|
||||||
@@ -112,17 +113,23 @@ public class SettleService {
|
|||||||
log.info("正在结算中,稍等!");
|
log.info("正在结算中,稍等!");
|
||||||
return SettleResp.builder().nextRun(true).build();
|
return SettleResp.builder().nextRun(true).build();
|
||||||
}
|
}
|
||||||
boolean lockFlag = clientLock.tryLock();
|
boolean lockFlag = false;
|
||||||
if(!lockFlag){
|
|
||||||
log.info("正在结算中,稍等!");
|
|
||||||
return SettleResp.builder().nextRun(true).build();
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
|
lockFlag = clientLock.tryLock(5,60, TimeUnit.SECONDS);
|
||||||
|
if(!lockFlag){
|
||||||
|
log.info("正在结算中,稍等!");
|
||||||
|
return SettleResp.builder().nextRun(true).build();
|
||||||
|
}
|
||||||
return deal(room);
|
return deal(room);
|
||||||
}finally {
|
} catch (InterruptedException e) {
|
||||||
clientLock.unlock();
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
clientLock.unlock();
|
||||||
|
}catch (Exception e){
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|||||||
@@ -2,22 +2,41 @@ package com.ruoyi.cai.ws.util;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.ruoyi.cai.ws.dto.WsR;
|
import com.ruoyi.cai.ws.dto.WsR;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
public class RoomWebSocketUtil {
|
public class RoomWebSocketUtil {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SendMessageI sendMessage;
|
||||||
|
|
||||||
|
private static SendMessageI sendMessageStatic;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init(){
|
||||||
|
sendMessageStatic = sendMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void sendSendMessage(String sessionKey, WsR r){
|
public static void sendSendMessage(String sessionKey, WsR r){
|
||||||
WebSocketUtils.sendMessage(sessionKey, JSON.toJSONString(r));
|
sendMessageStatic.sendMessage(sessionKey, JSON.toJSONString(r));
|
||||||
|
// WebSocketUtils.sendMessage(sessionKey, JSON.toJSONString(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendSendMessage(WebSocketSession sessionKey, WsR r){
|
public static void sendSendMessage(WebSocketSession sessionKey, WsR r){
|
||||||
WebSocketUtils.sendMessage(sessionKey, JSON.toJSONString(r));
|
sendMessageStatic.sendMessage(sessionKey.getId(), JSON.toJSONString(r));
|
||||||
|
// WebSocketUtils.sendMessage(sessionKey, JSON.toJSONString(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendSendMessage(List<String> sessionKey, WsR r){
|
public static void sendSendMessage(List<String> sessionKey, WsR r){
|
||||||
for (String s : sessionKey) {
|
for (String s : sessionKey) {
|
||||||
WebSocketUtils.sendMessage(s, JSON.toJSONString(r));
|
sendMessageStatic.sendMessage(s, JSON.toJSONString(r));
|
||||||
|
// WebSocketUtils.sendMessage(s, JSON.toJSONString(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.ruoyi.cai.ws.util;
|
||||||
|
|
||||||
|
|
||||||
|
public interface SendMessageI {
|
||||||
|
void sendMessage(String sessionKey, String message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ruoyi.cai.ws.util;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SessionObj {
|
||||||
|
private String sessionKey;
|
||||||
|
private String data;
|
||||||
|
}
|
||||||
@@ -45,7 +45,9 @@ public class WebSocketUtils {
|
|||||||
public static boolean close(WebSocketSession session) {
|
public static boolean close(WebSocketSession session) {
|
||||||
if(session != null){
|
if(session != null){
|
||||||
try {
|
try {
|
||||||
session.close();
|
if(session.isOpen()){
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("关闭ws失败,session={}",session,e);
|
log.error("关闭ws失败,session={}",session,e);
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.ruoyi.consumer;
|
||||||
|
|
||||||
|
import com.ruoyi.cai.ws.util.SessionObj;
|
||||||
|
import com.ruoyi.cai.ws.util.WebSocketUtils;
|
||||||
|
import org.redisson.api.RBlockingQueue;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class RedisConsumer {
|
||||||
|
@Autowired
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init(){
|
||||||
|
ExecutorService executorService = Executors.newFixedThreadPool(20);
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
executorService.execute(() -> {
|
||||||
|
while (true){
|
||||||
|
try {
|
||||||
|
System.out.println();
|
||||||
|
run();
|
||||||
|
System.out.println();
|
||||||
|
}catch (Exception e){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void run() throws InterruptedException {
|
||||||
|
RBlockingQueue<SessionObj> sessionPush = redissonClient.getBlockingQueue("sessionPush");
|
||||||
|
SessionObj poll = sessionPush.take();
|
||||||
|
RLock lock = redissonClient.getLock("sessionPushLock:" + poll.getSessionKey());
|
||||||
|
try {
|
||||||
|
lock.tryLock(5,5, TimeUnit.SECONDS);
|
||||||
|
WebSocketUtils.sendMessage(poll.getSessionKey(), poll.getData());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
lock.unlock();
|
||||||
|
}catch (Exception e){
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package com.ruoyi.consumer;
|
|||||||
import com.ruoyi.cai.mq.AmqpWsProducer;
|
import com.ruoyi.cai.mq.AmqpWsProducer;
|
||||||
import com.ruoyi.cai.mq.constant.ws.RoomCheckDelayWsMqConstant;
|
import com.ruoyi.cai.mq.constant.ws.RoomCheckDelayWsMqConstant;
|
||||||
import com.ruoyi.cai.ws.job.JobResp;
|
import com.ruoyi.cai.ws.job.JobResp;
|
||||||
import com.ruoyi.job.RoomCheckJobService;
|
import com.ruoyi.service.RoomCheckJobService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -17,22 +17,21 @@ public class RoomCheckDelayMqConsumer {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RoomCheckJobService roomCheckJobService;
|
private RoomCheckJobService roomCheckJobService;
|
||||||
|
|
||||||
@RabbitListener(queues = RoomCheckDelayWsMqConstant.QUEUE_NAME
|
@RabbitListener(queues = RoomCheckDelayWsMqConstant.QUEUE_NAME, concurrency = "30")
|
||||||
,containerFactory = "customContainerFactory")
|
|
||||||
public void sendRoomCheck(String roomIdStr) {
|
public void sendRoomCheck(String roomIdStr) {
|
||||||
log.info("开始执行房间检测: roomId={}",roomIdStr);
|
log.info("开始执行房间检测: roomId={}", roomIdStr);
|
||||||
try {
|
try {
|
||||||
Long roomId = Long.valueOf(roomIdStr);
|
Long roomId = Long.valueOf(roomIdStr);
|
||||||
JobResp resp = roomCheckJobService.checkRoom(roomId);
|
JobResp resp = roomCheckJobService.checkRoom(roomId);
|
||||||
if(resp.isNextCreateJob()){
|
if (resp.isNextCreateJob()) {
|
||||||
// 1分钟后继续执行
|
// 1分钟后继续执行
|
||||||
log.info("1分钟后继续执行房间检测: roomId={}",roomIdStr);
|
log.info("1分钟后继续执行房间检测: roomId={}", roomIdStr);
|
||||||
amqpWsProducer.sendRoomCheckDelay(roomIdStr,60);
|
amqpWsProducer.sendRoomCheckDelay(roomIdStr, 60);
|
||||||
}
|
}
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
log.error("每分钟定时检测房间失败! roomId={}",roomIdStr);
|
log.error("每分钟定时检测房间失败! roomId={}", roomIdStr);
|
||||||
}finally {
|
} finally {
|
||||||
log.info("结束执行房间检测: roomId={}",roomIdStr);
|
log.info("结束执行房间检测: roomId={}", roomIdStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ public class RoomSettleDelayMqConsumer {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AmqpWsProducer amqpWsProducer;
|
private AmqpWsProducer amqpWsProducer;
|
||||||
|
|
||||||
@RabbitListener(queues = RoomSettleDelayWsMqConstant.QUEUE_NAME
|
@RabbitListener(queues = RoomSettleDelayWsMqConstant.QUEUE_NAME,concurrency = "30")
|
||||||
,containerFactory = "customContainerFactory")
|
|
||||||
public void checkTimeOutMq(String message) {
|
public void checkTimeOutMq(String message) {
|
||||||
log.info("开始执行预扣费: " + message);
|
log.info("开始执行预扣费: " + message);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.ruoyi.consumer;
|
||||||
|
|
||||||
|
import com.ruoyi.cai.ws.util.SendMessageI;
|
||||||
|
import com.ruoyi.cai.ws.util.SessionObj;
|
||||||
|
import org.redisson.api.RBlockingQueue;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SendMessageWsImpl implements SendMessageI {
|
||||||
|
@Autowired
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String sessionKey, String message){
|
||||||
|
RBlockingQueue<SessionObj> sessionPush = redissonClient.getBlockingQueue("sessionPush");
|
||||||
|
SessionObj sessionObj = new SessionObj();
|
||||||
|
sessionObj.setSessionKey(sessionKey);
|
||||||
|
sessionObj.setData(message);
|
||||||
|
try {
|
||||||
|
sessionPush.put(sessionObj);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.job;
|
package com.ruoyi.job;
|
||||||
|
|
||||||
import com.ruoyi.cai.ws.cache.OnlineDataCache;
|
import com.ruoyi.cai.ws.cache.OnlineDataCache;
|
||||||
|
import com.ruoyi.service.RoomCheckJobService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
@@ -20,7 +21,7 @@ public class RoomCheckJob {
|
|||||||
/**
|
/**
|
||||||
* 每 7分钟执行一次
|
* 每 7分钟执行一次
|
||||||
*/
|
*/
|
||||||
@Scheduled(fixedDelay = 7,timeUnit = TimeUnit.MINUTES)
|
@Scheduled(fixedDelay = 5,timeUnit = TimeUnit.MINUTES)
|
||||||
public void run(){
|
public void run(){
|
||||||
Set<String> all = onlineDataCache.getAll();
|
Set<String> all = onlineDataCache.getAll();
|
||||||
for (String roomIdS : all) {
|
for (String roomIdS : all) {
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
package com.ruoyi.job;
|
||||||
|
|
||||||
|
import com.alibaba.ttl.threadpool.TtlExecutors;
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import com.ruoyi.cai.ws.cache.OnlineDataCache;
|
||||||
|
import com.ruoyi.service.RoomCheckJobService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class RoomCheckJobBack {
|
||||||
|
@Autowired
|
||||||
|
private OnlineDataCache onlineDataCache;
|
||||||
|
@Autowired
|
||||||
|
private RoomCheckJobService roomCheckJobService;
|
||||||
|
|
||||||
|
private final static int CPU_NUM = 100;
|
||||||
|
|
||||||
|
public static Executor CHECK_ROOM_EXECUTOR;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// 丢弃队列
|
||||||
|
ThreadPoolExecutor syncExecutor = new ThreadPoolExecutor(CPU_NUM,
|
||||||
|
CPU_NUM * 2,
|
||||||
|
5,
|
||||||
|
TimeUnit.SECONDS,
|
||||||
|
new SynchronousQueue<>(),
|
||||||
|
init("roomCheckJob-%d"),
|
||||||
|
new ThreadPoolExecutor.DiscardPolicy());
|
||||||
|
CHECK_ROOM_EXECUTOR = TtlExecutors.getTtlExecutor(syncExecutor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ThreadFactory init(String nameFormat){
|
||||||
|
return new ThreadFactoryBuilder().setNameFormat(nameFormat).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ThreadPoolExecutor initExecutor(int corePoolSize, int maxPoolSize, int keepAliveTime, TimeUnit timeUnit,
|
||||||
|
BlockingQueue<Runnable> workQueue, String nameFormat){
|
||||||
|
return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue,
|
||||||
|
init(nameFormat));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 每 1分钟执行一次
|
||||||
|
*//*
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 3,timeUnit = TimeUnit.MINUTES)
|
||||||
|
// @PostConstruct
|
||||||
|
public void run(){
|
||||||
|
while (true) {
|
||||||
|
Set<String> all = onlineDataCache.getAll();
|
||||||
|
for (String roomIdS : all) {
|
||||||
|
try {
|
||||||
|
Long roomId = Long.valueOf(roomIdS);
|
||||||
|
CHECK_ROOM_EXECUTOR.execute(() -> {
|
||||||
|
roomCheckJobService.checkRoom(roomId);
|
||||||
|
});
|
||||||
|
}catch (Exception e){
|
||||||
|
log.info("房间检测失败!需要开发排查问题 roomId={}", roomIdS, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
package com.ruoyi.job;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import com.alibaba.ttl.threadpool.TtlExecutors;
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import com.ruoyi.cai.ws.cache.OnlineDataCache;
|
||||||
|
import com.ruoyi.cai.ws.constant.RedisConstant;
|
||||||
|
import com.ruoyi.cai.ws.service.SettleService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RBucket;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class RoomKouQianJobBak {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OnlineDataCache onlineDataCache;
|
||||||
|
@Autowired
|
||||||
|
private SettleService settleService;
|
||||||
|
@Autowired
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
private final static int CPU_NUM = 300;
|
||||||
|
|
||||||
|
public static Executor CHECK_ROOM_EXECUTOR;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// 丢弃队列
|
||||||
|
ThreadPoolExecutor syncExecutor = new ThreadPoolExecutor(CPU_NUM,
|
||||||
|
CPU_NUM * 2,
|
||||||
|
5,
|
||||||
|
TimeUnit.SECONDS,
|
||||||
|
new SynchronousQueue<>(),
|
||||||
|
init("RoomKouQianJob-%d"),
|
||||||
|
new ThreadPoolExecutor.DiscardPolicy());
|
||||||
|
CHECK_ROOM_EXECUTOR = TtlExecutors.getTtlExecutor(syncExecutor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ThreadFactory init(String nameFormat) {
|
||||||
|
return new ThreadFactoryBuilder().setNameFormat(nameFormat).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ThreadPoolExecutor initExecutor(int corePoolSize, int maxPoolSize, int keepAliveTime, TimeUnit timeUnit,
|
||||||
|
BlockingQueue<Runnable> workQueue, String nameFormat) {
|
||||||
|
return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue,
|
||||||
|
init(nameFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 每 1分钟执行一次
|
||||||
|
*//*
|
||||||
|
|
||||||
|
// @Scheduled(fixedDelay = 7,timeUnit = TimeUnit.MINUTES)
|
||||||
|
@PostConstruct
|
||||||
|
public void run() {
|
||||||
|
ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||||
|
executorService.execute(() -> {
|
||||||
|
while (true) {
|
||||||
|
Set<String> all = onlineDataCache.getAll();
|
||||||
|
for (String roomIdS : all) {
|
||||||
|
try {
|
||||||
|
Long roomId = Long.valueOf(roomIdS);
|
||||||
|
CHECK_ROOM_EXECUTOR.execute(() -> {
|
||||||
|
RBucket<String> bucket = redissonClient.getBucket(RedisConstant.REDIS_P + "koufeiLock-" + roomId);
|
||||||
|
boolean lock = bucket.setIfExists(RandomUtil.randomString(10), Duration.ofMinutes(1));
|
||||||
|
if (!lock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean success = settleService.withholdingFee(roomId);
|
||||||
|
if (!success) {
|
||||||
|
bucket.delete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("房间检测失败!需要开发排查问题 roomId={}", roomIdS, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.ruoyi.job;
|
package com.ruoyi.service;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
@@ -48,10 +48,10 @@ public class RoomCheckJobService {
|
|||||||
return JobResp.builder().nextCreateJob(false).build();
|
return JobResp.builder().nextCreateJob(false).build();
|
||||||
}
|
}
|
||||||
// 检查是否三分钟没有接听
|
// 检查是否三分钟没有接听
|
||||||
log.info("调试日志:检查是否三分钟没有接听 roomId={}" , roomId);
|
log.info("调试日志:检查是否2分钟没有接听 roomId={}" , roomId);
|
||||||
JobResp resp = this.checkRoomCallerTimeOut(room);
|
JobResp resp = this.checkRoomCallerTimeOut(room);
|
||||||
if(!resp.isNextCreateJob()){
|
if(!resp.isNextCreateJob()){
|
||||||
log.info("调试日志:三分钟没有接听,可能关闭了 roomId={}" , roomId);
|
log.info("调试日志:2分钟没有接听,可能关闭了 roomId={}" , roomId);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
// 检查心跳
|
// 检查心跳
|
||||||
@@ -126,9 +126,9 @@ public class RoomCheckJobService {
|
|||||||
Long connectTimeCaller = callUserData.getConnectTime();
|
Long connectTimeCaller = callUserData.getConnectTime();
|
||||||
Long connectTimeReceiver = receiverUserData.getConnectTime();
|
Long connectTimeReceiver = receiverUserData.getConnectTime();
|
||||||
boolean timeOut = false;
|
boolean timeOut = false;
|
||||||
if(connectTimeCaller != null && DateUtil.currentSeconds() - connectTimeCaller > 180){
|
if(connectTimeCaller != null && DateUtil.currentSeconds() - connectTimeCaller > 120){
|
||||||
timeOut = true;
|
timeOut = true;
|
||||||
}else if(connectTimeReceiver != null && DateUtil.currentSeconds() - connectTimeReceiver > 180){
|
}else if(connectTimeReceiver != null && DateUtil.currentSeconds() - connectTimeReceiver > 120){
|
||||||
timeOut = true;
|
timeOut = true;
|
||||||
}
|
}
|
||||||
if(timeOut){
|
if(timeOut){
|
||||||
@@ -32,9 +32,9 @@ spring:
|
|||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
||||||
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
||||||
url: jdbc:mysql://localhost:3306/cai-new?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
url: jdbc:mysql://124.222.254.188:4306/cai-v2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||||
username: root
|
username: root
|
||||||
password: 123
|
password: 383200134
|
||||||
# 从库数据源
|
# 从库数据源
|
||||||
slave:
|
slave:
|
||||||
lazy: true
|
lazy: true
|
||||||
@@ -69,7 +69,7 @@ spring:
|
|||||||
# 数据库索引
|
# 数据库索引
|
||||||
database: 12
|
database: 12
|
||||||
# 密码(如没有密码请注释掉)
|
# 密码(如没有密码请注释掉)
|
||||||
password: 123
|
password: 383200134
|
||||||
# 连接超时时间
|
# 连接超时时间
|
||||||
timeout: 15s
|
timeout: 15s
|
||||||
# 是否开启ssl
|
# 是否开启ssl
|
||||||
@@ -102,18 +102,18 @@ mail:
|
|||||||
enabled: false
|
enabled: false
|
||||||
spring:
|
spring:
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
addresses: 127.0.0.1 #ip地址
|
addresses: 124.222.254.188 #ip地址
|
||||||
username: admin # 账号
|
username: admin # 账号
|
||||||
password: 123 # 密码
|
password: 383200134 # 密码
|
||||||
port: 5672
|
port: 5672
|
||||||
virtual-host: /cai-dev
|
virtual-host: /cai-dev
|
||||||
agora:
|
agora:
|
||||||
app-id: 58ff3a37d91d48c7a8ef7a56fb8f62d0
|
app-id: 58ff3a37d91d48c7a8ef7a56fb8f62d0123
|
||||||
key: 0cca1a53262c4c74b0a8c653a9b7540e
|
key: 0cca1a53262c4c74b0a8c653a9b7540e123
|
||||||
secret: 4a4f734285f34aea86cef63b2a186f27
|
secret: 4a4f734285f34aea86cef63b2a186f27123
|
||||||
yunxin:
|
yunxin:
|
||||||
app-key: 0aaefeb8a80a9889987c5346244b58e2
|
app-key: 0aaefeb8a80a9889987c5346244b58e2123
|
||||||
app-secret: 470345ca2832
|
app-secret: 470345ca2832123
|
||||||
springdoc:
|
springdoc:
|
||||||
api-docs:
|
api-docs:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|||||||
Reference in New Issue
Block a user