diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyChannel.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyChannel.java new file mode 100644 index 00000000..7443e7b5 --- /dev/null +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyChannel.java @@ -0,0 +1,80 @@ +package com.aizuda.easy.retry.client.core.client.netty; + +import cn.hutool.core.util.IdUtil; +import com.aizuda.easy.retry.client.core.cache.GroupVersionCache; +import com.aizuda.easy.retry.client.core.config.EasyRetryProperties; +import com.aizuda.easy.retry.common.core.context.SpringContext; +import com.aizuda.easy.retry.common.core.enums.HeadersEnum; +import com.aizuda.easy.retry.common.core.log.LogUtils; +import com.aizuda.easy.retry.common.core.util.HostUtils; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpVersion; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.web.ServerProperties; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.Optional; + +/** + * @author www.byteblogs.com + * @date 2023-05-13 + * @since 1.3.0 + */ +@Slf4j +public class NettyChannel { + + private static final String HOST_ID = IdUtil.simpleUUID(); + private static final String HOST_IP = HostUtils.getIp(); + + private static Channel CHANNEL; + + public static void setChannel(Channel channel) { + NettyChannel.CHANNEL = channel; + } + + /** + * 发送数据 + * + * @param method 请求方式 + * @param url url地址 + * @param body 请求的消息体 + * @throws InterruptedException + */ + public static void send(HttpMethod method, String url, String body) throws InterruptedException { + + if (Objects.isNull(CHANNEL)) { + LogUtils.info(log, "send message but channel is null url:[{}] method:[{}] body:[{}] ", url, method, body); + return; + } + + // 配置HttpRequest的请求数据和一些配置信息 + FullHttpRequest request = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, method, url, Unpooled.wrappedBuffer(body.getBytes(StandardCharsets.UTF_8))); + + ServerProperties serverProperties = SpringContext.CONTEXT.getBean(ServerProperties.class); + + request.headers() + .set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + //开启长连接 + .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE) + //设置传递请求内容的长度 + .set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes()) + .set(HeadersEnum.HOST_ID.getKey(), HOST_ID) + .set(HeadersEnum.HOST_IP.getKey(), HOST_IP) + .set(HeadersEnum.GROUP_NAME.getKey(), EasyRetryProperties.getGroup()) + .set(HeadersEnum.CONTEXT_PATH.getKey(), Optional.ofNullable(serverProperties.getServlet().getContextPath()).orElse("/")) + .set(HeadersEnum.HOST_PORT.getKey(), Optional.ofNullable(serverProperties.getPort()).orElse(8080)) + .set(HeadersEnum.VERSION.getKey(), GroupVersionCache.getVersion()) + ; + + //发送数据 + CHANNEL.writeAndFlush(request).sync(); + } +} diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyHttpClientHandler.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyHttpClientHandler.java index 66a33804..d45ffd33 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyHttpClientHandler.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyHttpClientHandler.java @@ -25,11 +25,17 @@ import java.util.concurrent.TimeUnit; public class NettyHttpClientHandler extends SimpleChannelInboundHandler { private NettyClient client; - public NettyHttpClientHandler() { + private NettyHttpConnectClient nettyHttpConnectClient; + + public NettyHttpClientHandler(NettyHttpConnectClient nettyHttpConnectClient) { + client = RequestBuilder.newBuilder() .client(NettyClient.class) .callback(nettyResult -> LogUtils.info(log,"heartbeat check requestId:[{}]", nettyResult.getRequestId())) .build(); + + this.nettyHttpConnectClient = nettyHttpConnectClient; + } @Override @@ -53,13 +59,14 @@ public class NettyHttpClientHandler extends SimpleChannelInboundHandler { - EasyRetryProperties easyRetryProperties = SpringContext.getBeanByType(EasyRetryProperties.class); - EasyRetryProperties.ServerConfig server = easyRetryProperties.getServer(); - LogUtils.info(log, "Reconnecting to:" + server.getHost() + ":" + server.getPort()); - NettyHttpConnectClient.connect(); + try { + nettyHttpConnectClient.reconnect(); + } catch (Exception e) { + LogUtils.error(log, "reconnect error ", e); + } + }, 10, TimeUnit.SECONDS); @@ -91,7 +98,7 @@ public class NettyHttpClientHandler extends SimpleChannelInboundHandler { + Throwable cause = future.cause(); + if (cause != null) { + exceptionHandler(cause); + } else { + channel = channelFuture.channel(); + if (channel != null && channel.isActive()) { + log.info("Netty client {} reconnect to server", channel.localAddress()); + NettyChannel.setChannel(getChannel()); + } + } + }); + } + + /** + * 连接失败处理 + * + * @param cause + */ + private void exceptionHandler(Throwable cause) { + if (cause instanceof ConnectException) { + log.error("connect error:{}", cause.getMessage()); + } else if (cause instanceof ClosedChannelException) { + log.error("connect error:{}", "client has destroy"); + } else { + log.error("connect error:", cause); + } + } + + @Override public void close() { - nioEventLoopGroup.shutdownGracefully(); - } - - public static void connect(){ - channel = bootstrap.connect().addListener((ChannelFutureListener) future -> { - if (future.cause() != null){ - LogUtils.debug(log,"operationComplete", future.cause()); - } - }).channel(); - } - - public static void send(HttpMethod method, String url, String body) throws InterruptedException { - - if (Objects.isNull(channel)) { - LogUtils.debug(log,"channel is null"); - return; + if (channel != null) { + channel.close(); } - - // 配置HttpRequest的请求数据和一些配置信息 - FullHttpRequest request = new DefaultFullHttpRequest( - HttpVersion.HTTP_1_0, method, url, Unpooled.wrappedBuffer(body.getBytes(StandardCharsets.UTF_8))); - - ServerProperties serverProperties = SpringContext.CONTEXT.getBean(ServerProperties.class); - - request.headers() - .set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - //开启长连接 - .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE) - //设置传递请求内容的长度 - .set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes()) - .set(HeadersEnum.HOST_ID.getKey(), HOST_ID) - .set(HeadersEnum.HOST_IP.getKey(), HOST_IP) - .set(HeadersEnum.GROUP_NAME.getKey(), EasyRetryProperties.getGroup()) - .set(HeadersEnum.CONTEXT_PATH.getKey(), Optional.ofNullable(serverProperties.getServlet().getContextPath()).orElse("/")) - .set(HeadersEnum.HOST_PORT.getKey(), Optional.ofNullable(serverProperties.getPort()).orElse(8080)) - .set(HeadersEnum.VERSION.getKey(), GroupVersionCache.getVersion()) - ; - - //发送数据 - channel.writeAndFlush(request).sync(); - } - - public static void sendSync(HttpMethod method, String url, String body) throws InterruptedException { - - if (Objects.isNull(channel)) { - LogUtils.debug(log,"channel is null"); - return; + if (nioEventLoopGroup != null) { + nioEventLoopGroup.shutdownGracefully(); } - - // 配置HttpRequest的请求数据和一些配置信息 - FullHttpRequest request = new DefaultFullHttpRequest( - HttpVersion.HTTP_1_0, method, url, Unpooled.wrappedBuffer(body.getBytes(StandardCharsets.UTF_8))); - - ServerProperties serverProperties = SpringContext.CONTEXT.getBean(ServerProperties.class); - - request.headers() - .set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - //开启长连接 - .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE) - //设置传递请求内容的长度 - .set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes()) - .set(HeadersEnum.HOST_ID.getKey(), HOST_ID) - .set(HeadersEnum.HOST_IP.getKey(), HOST_IP) - .set(HeadersEnum.GROUP_NAME.getKey(), EasyRetryProperties.getGroup()) - .set(HeadersEnum.CONTEXT_PATH.getKey(), Optional.ofNullable(serverProperties.getServlet().getContextPath()).orElse("/")) - .set(HeadersEnum.HOST_PORT.getKey(), Optional.ofNullable(serverProperties.getPort()).orElse(8080)) - .set(HeadersEnum.VERSION.getKey(), GroupVersionCache.getVersion()) - ; - - //发送数据 - channel.writeAndFlush(request).sync(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } + + public Channel getChannel() { + return channel; + } } diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/RpcContext.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/RpcContext.java index 28c74dde..0b593fea 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/RpcContext.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/RpcContext.java @@ -20,11 +20,11 @@ import java.util.function.Consumer; @Slf4j public class RpcContext { - private static final ConcurrentMap COMPLETABLE_FUTURE = new ConcurrentHashMap<>(); + private static final ConcurrentMap COMPLETABLE_FUTURE = new ConcurrentHashMap<>(); - private static final ConcurrentMap CALLBACK_CONSUMER = new ConcurrentHashMap<>(); + private static final ConcurrentMap CALLBACK_CONSUMER = new ConcurrentHashMap<>(); - public static void invoke(String requestId, NettyResult nettyResult) { + public static void invoke(Long requestId, NettyResult nettyResult) { try { // 同步请求同步返回 @@ -41,7 +41,7 @@ public class RpcContext { } - public static void setCompletableFuture(String id, CompletableFuture completableFuture, Consumer callable) { + public static void setCompletableFuture(long id, CompletableFuture completableFuture, Consumer callable) { if (Objects.nonNull(completableFuture)) { COMPLETABLE_FUTURE.put(id, completableFuture); } @@ -52,19 +52,19 @@ public class RpcContext { } - public static void setCompletableFuture(String id, Consumer callable) { + public static void setCompletableFuture(Long id, Consumer callable) { setCompletableFuture(id, null, callable); } - public static void setCompletableFuture(String id, CompletableFuture completableFuture) { + public static void setCompletableFuture(Long id, CompletableFuture completableFuture) { setCompletableFuture(id, completableFuture, null); } - public static CompletableFuture getCompletableFuture(String id) { + public static CompletableFuture getCompletableFuture(Long id) { return COMPLETABLE_FUTURE.get(id); } - public static Consumer getConsumer(String id) { + public static Consumer getConsumer(Long id) { return CALLBACK_CONSUMER.get(id); } } diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/proxy/ClientInvokeHandler.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/proxy/ClientInvokeHandler.java index c37332a0..346126b5 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/proxy/ClientInvokeHandler.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/proxy/ClientInvokeHandler.java @@ -3,7 +3,7 @@ package com.aizuda.easy.retry.client.core.client.proxy; import cn.hutool.core.date.StopWatch; import cn.hutool.core.lang.Assert; import com.aizuda.easy.retry.client.core.annotation.Mapping; -import com.aizuda.easy.retry.client.core.client.netty.NettyHttpConnectClient; +import com.aizuda.easy.retry.client.core.client.netty.NettyChannel; import com.aizuda.easy.retry.client.core.client.netty.RpcContext; import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException; import com.aizuda.easy.retry.common.core.log.LogUtils; @@ -28,10 +28,10 @@ import java.util.function.Consumer; @Slf4j public class ClientInvokeHandler implements InvocationHandler { - private Consumer consumer; - private boolean async; - private long timeout; - private TimeUnit unit; + private final Consumer consumer; + private final boolean async; + private final long timeout; + private final TimeUnit unit; public ClientInvokeHandler(boolean async, long timeout, TimeUnit unit, Consumer consumer) { this.consumer = consumer; @@ -46,26 +46,23 @@ public class ClientInvokeHandler implements InvocationHandler { Mapping annotation = method.getAnnotation(Mapping.class); EasyRetryRequest easyRetryRequest = new EasyRetryRequest(args); - sw.start("request start " + easyRetryRequest.getRequestId()); + sw.start("request start " + easyRetryRequest.getReqId()); CompletableFuture completableFuture = null; if (async) { - RpcContext.setCompletableFuture(easyRetryRequest.getRequestId(), consumer); + RpcContext.setCompletableFuture(easyRetryRequest.getReqId(), consumer); } else { completableFuture = new CompletableFuture<>(); - RpcContext.setCompletableFuture(easyRetryRequest.getRequestId(), completableFuture); + RpcContext.setCompletableFuture(easyRetryRequest.getReqId(), completableFuture); } try { - NettyHttpConnectClient.send(HttpMethod.valueOf(annotation.method().name()), annotation.path(), - JsonUtil.toJsonString(easyRetryRequest)); - } catch (Exception e) { - throw e; + NettyChannel.send(HttpMethod.valueOf(annotation.method().name()), annotation.path(), easyRetryRequest.toString()); } finally { sw.stop(); } - LogUtils.info(log,"request complete requestId:[{}] 耗时:[{}ms]", easyRetryRequest.getRequestId(), sw.getTotalTimeMillis()); + LogUtils.info(log,"request complete requestId:[{}] 耗时:[{}ms]", easyRetryRequest.getReqId(), sw.getTotalTimeMillis()); if (async) { return null; } else { diff --git a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/EasyRetryRequest.java b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/EasyRetryRequest.java index 00a26c1c..83e34297 100644 --- a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/EasyRetryRequest.java +++ b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/EasyRetryRequest.java @@ -1,8 +1,10 @@ package com.aizuda.easy.retry.common.core.model; +import com.aizuda.easy.retry.common.core.util.JsonUtil; import lombok.Data; -import java.util.UUID; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLong; /** * @author www.byteblogs.com @@ -12,21 +14,26 @@ import java.util.UUID; @Data public class EasyRetryRequest { - private String requestId; + private static final AtomicLong REQUEST_ID = new AtomicLong(0); + + private long reqId; private Object[] args; public EasyRetryRequest(Object... args) { this.args = args; - this.requestId = generateRequestId(); + this.reqId = newId(); + } + + private static long newId() { + return REQUEST_ID.getAndIncrement(); } public EasyRetryRequest() { - } - public String generateRequestId() { - return UUID.randomUUID().toString(); + @Override + public String toString() { + return JsonUtil.toJsonString(this); } - } diff --git a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/NettyResult.java b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/NettyResult.java index 8211ef23..cf229814 100644 --- a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/NettyResult.java +++ b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/model/NettyResult.java @@ -9,9 +9,9 @@ import lombok.Data; @Data public class NettyResult extends Result { - private String requestId; + private long requestId; - public NettyResult(int status, String message, Object data, String requestId) { + public NettyResult(int status, String message, Object data, long requestId) { super(status, message, data); this.requestId = requestId; } @@ -19,7 +19,7 @@ public class NettyResult extends Result { public NettyResult() { } - public NettyResult(Object data, String requestId) { + public NettyResult(Object data, long requestId) { super(data); this.requestId = requestId; } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/BeatHttpRequestHandler.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/BeatHttpRequestHandler.java index fb2be1c8..a061ef30 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/BeatHttpRequestHandler.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/BeatHttpRequestHandler.java @@ -1,6 +1,7 @@ package com.aizuda.easy.retry.server.server.handler; import cn.hutool.core.net.url.UrlQuery; +import com.aizuda.easy.retry.common.core.log.LogUtils; import com.aizuda.easy.retry.server.support.handler.ClientRegisterHandler; import com.aizuda.easy.retry.common.core.model.NettyResult; import com.aizuda.easy.retry.common.core.model.EasyRetryRequest; @@ -36,8 +37,8 @@ public class BeatHttpRequestHandler extends GetHttpRequestHandler { @Override public String doHandler(String content, UrlQuery query, HttpHeaders headers) { - log.info("心跳检查 content:[{}]", query.toString()); + LogUtils.info(log,"Beat check content:[{}]", content); EasyRetryRequest retryRequest = JsonUtil.parseObject(content, EasyRetryRequest.class); - return JsonUtil.toJsonString(new NettyResult("PONG", retryRequest.getRequestId())); + return JsonUtil.toJsonString(new NettyResult("PONG", retryRequest.getReqId())); } } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ConfigHttpRequestHandler.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ConfigHttpRequestHandler.java index 94ff5399..ab304e94 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ConfigHttpRequestHandler.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ConfigHttpRequestHandler.java @@ -44,6 +44,6 @@ public class ConfigHttpRequestHandler extends GetHttpRequestHandler { EasyRetryRequest retryRequest = JsonUtil.parseObject(content, EasyRetryRequest.class); String groupName = headers.get(HeadersEnum.GROUP_NAME.getKey()); ConfigDTO configDTO = configAccess.getConfigInfo(groupName); - return JsonUtil.toJsonString(new NettyResult(JsonUtil.toJsonString(configDTO), retryRequest.getRequestId())); + return JsonUtil.toJsonString(new NettyResult(JsonUtil.toJsonString(configDTO), retryRequest.getReqId())); } } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java index 522a882b..ca5f045a 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java @@ -48,10 +48,10 @@ public class ReportRetryInfoHttpRequestHandler extends PostHttpRequestHandler { Object[] args = retryRequest.getArgs(); Boolean aBoolean = retryService.batchReportRetry(JsonUtil.parseList(JsonUtil.toJsonString(args[0]), RetryTaskDTO.class)); - return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), "批量上报重试数据处理成功", aBoolean, retryRequest.getRequestId())); + return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), "批量上报重试数据处理成功", aBoolean, retryRequest.getReqId())); } catch (Exception e) { LogUtils.error(log, "批量上报重试数据失败", e); - return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), e.getMessage(), null, retryRequest.getRequestId())); + return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), e.getMessage(), null, retryRequest.getReqId())); } } } diff --git a/frontend/src/views/config/basicConfigForm/BasicConfigForm.vue b/frontend/src/views/config/basicConfigForm/BasicConfigForm.vue index f31cbf12..a8ee8021 100644 --- a/frontend/src/views/config/basicConfigForm/BasicConfigForm.vue +++ b/frontend/src/views/config/basicConfigForm/BasicConfigForm.vue @@ -102,6 +102,7 @@ export default { message: res.message }) this.$refs.notify.reset() + this.$router.go(-1) } }) }).catch(() => { diff --git a/frontend/src/views/config/basicConfigForm/GroupForm.vue b/frontend/src/views/config/basicConfigForm/GroupForm.vue index 9785738b..9d7d376c 100644 --- a/frontend/src/views/config/basicConfigForm/GroupForm.vue +++ b/frontend/src/views/config/basicConfigForm/GroupForm.vue @@ -3,18 +3,21 @@ - + + @@ -49,6 +52,7 @@