心跳钩子被多次执行
KING754 opened this issue · comments
你的问题 | 使用场景
在对外服上加了钩子。然后通过Client连过去。发现callback被执行了三次。
hook:
@Slf4j
public class HeartBeatHook implements SocketIdleHook {
@Override
public boolean callback(UserSession userSession, IdleStateEvent idleStateEvent) {
log.info("heart check id:{}",userSession.getUserId());
return false;
}
@Override
public void pongBefore(BarMessage idleMessage) {log.info("receive pongBefore:{}",idleMessage);
idleMessage.setData(DataCodecKit.encode(TimeKit.currentTimeMillis()));
}
}
ExternalServerConfig
@Component
@RequiredArgsConstructor
public class ExternalServerConfig {
private final AppConfig appConfig;
private final ServerUtil serverUtil;
public ExternalServer createExternalServer() {
if (!serverUtil.checkServerConfig(appConfig, true, true)) {
System.exit(0);
}
IoGameGlobalConfig.openTraceId = true;
IoGameGlobalConfig.externalLog = true;
IoGameGlobalConfig.broadcastLog = true;
IoGameGlobalConfig.openLog = true;
// 路由访问权限控制;https://www.yuque.com/iohao/game/nap5y8p5fevhv99y
extractedIgnore();
// 游戏对外服 - 构建器;https://www.yuque.com/iohao/game/ea6geg
DefaultExternalServerBuilder builder = DefaultExternalServer.newBuilder(appConfig.getPort())
.externalJoinEnum(this.getProtoByConfigOrDefault(appConfig.getProtoName())) //协议类型
.brokerAddress(new BrokerAddress(appConfig.getGatewayIP(), appConfig.getGatewayPort()));
builder.setting().setUserHook(new LogOutHook());
builder.setting().setIdleProcessSetting(this.getHeartBeatSetting());
// 构建游戏对外服
return builder.build();
}
private void extractedIgnore() {
AccessAuthenticationHook accessAuthenticationHook = ExternalGlobalConfig.accessAuthenticationHook;
accessAuthenticationHook.addIgnoreAuthCmd(E_ModuleId.E_M_Login_Id.value(), E_MsgId.E_Login.value());
}
private IdleProcessSetting getHeartBeatSetting(){
return new IdleProcessSetting()
// 心跳整体时间设置包括:readerIdleTime、writerIdleTime、allIdleTime
.setIdleTime(30)
.setIdleHook(new HeartBeatHook());
}
private ExternalJoinEnum getProtoByConfigOrDefault(String protoType) {
if (StrUtil.isEmpty(protoType)) {
return ExternalJoinEnum.TCP;
}
for (ExternalJoinEnum proto : ExternalJoinEnum.values()) {
if (proto.getName().equals(protoType)) {
return proto;
}
}
return ExternalJoinEnum.TCP;
}
}
InitServer
@Slf4j
@Component
@RequiredArgsConstructor
public class InitServer implements CommandLineRunner {
private final ExternalServerConfig gameExternal;
@Override
public void run(String... args) throws Exception {
ExternalServer server = gameExternal.createExternalServer();
server.startup();
}
}
boot:
@componentscan(basePackages = "com.bitdragon.*")
@SpringBootApplication
public class ExternalApplication {
public static void main(String[] args) {
SpringApplication.run(ExternalApplication.class, args);
}
}
client:
public static ClientRunOne initClient(){
ClientRunOne client = new ClientRunOne();
client.setJoinEnum(TCP);
client.setInputCommandRegions(InitClient.getAllCmdAction());
client.setConnectAddress(EXTERNAL_IP);
client.setConnectPort(EXTERNAL_PORT);
// client.idle(20);
return client;
}
private static List<InputCommandRegion> getAllCmdAction(){
return List.of(
new LoginCmd(),
new FriendListCmd(),
new TaskListCmd()
);
}
结果每隔30秒日志:
18:01:25.481 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:01:25.524 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:01:25.524 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:01:55.482 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:01:55.535 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:01:55.535 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:02:25.482 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:02:25.536 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
18:02:25.536 [iohao.com:external-netty-server-worker-1] [] INFO c.b.e.h.HeartBeatHook.callback(HeartBeatHook.java:17) heart check id:1779812137254780928
预期值
每30秒,应该只执行一次。
实际值
每30秒,执行了三次。
可以提供一个能运行的可复现的 demo 和复现步骤吗
上面的代码, 就是我有点问题的代码.然后好像没有特别的步骤.就是启动好几个服务之后,然后客户端启动起来,连过去.啥也不做(不发心跳).
我明天看一下,能不能拉一个单独工程试一下.
https://github.com/KING754/ioGameDemo
我刚刚用这个试了,还是三次。
启动server-gateway,server-external,server-login
然后启动客户端
30秒之后,server-external就会有三次日志出来了。
上传一个 zip 到这里吧。
我刚刚试了example/example-hook,也能复现出来.
修改1:DemoIdleHook.java的callback方法:
@Override
public boolean callback(UserSession userSession, IdleStateEvent event) {
log.info("receive heart beat call back!!!");
return false;
}
修改2:DemoHookClient.java
public static void main(String[] args) {
ClientUserConfigs.closeLog();
// 模拟请求数据
List<InputCommandRegion> inputCommandRegions = List.of(
new InternalRegion()
);
// 启动模拟客户端
new ClientRunOne()
.setInputCommandRegions(inputCommandRegions)
// 开启心跳,每 3 秒向服务器发送一次心跳消息
// .idle(3) //第二处修改,注释掉心跳发送
.startup();
}
然后运行:
DemoHookApplication.java
再运行:DemoHookClient.java
观察:DemoHookApplication控制台即可.
默认心跳配置的是 READER_IDLE、WRITER_IDLE、ALL_IDLE,触发时间都是大致相同的。
建议你在打印时,把 IdleStateEvent 也打印一下。
确实是这样,三个事件。因为我用的是setIdleTime(30)方法。
那像这样的话,我想想,我应该怎么使用。
没有注意到心跳有三种类型。
我只处理一种,其它两个不处理就好了。
谢谢。