apache / hertzbeat

Apache HertzBeat(incubating) is a real-time monitoring system with agentless, performance cluster, prometheus-compatible, custom monitoring and status page building capabilities.
https://hertzbeat.apache.org/
Apache License 2.0
5.35k stars 933 forks source link

[BUG] Plugin cannot be removed #2253

Closed pwallk closed 3 weeks ago

pwallk commented 1 month ago

Is there an existing issue for this?

Current Behavior

pr #2238 Plugins cannot be removed, either before or after packaging Clip_2024-07-09_11-00-58

Expected Behavior

the plugin can be removed and uninstalled from the JVM

Steps To Reproduce

No response

Environment

HertzBeat version(s): master
OS: windows 11
JRE: jdk17

Debug logs

2024-07-09 11:00:40.512 [http-nio-1157-exec-10] ERROR org.apache.hertzbeat.manager.support.GlobalExceptionHandler Line:252 - [monitor]-[unknown error happen]-java.nio.file.FileSystemException: D:\workspace\open\dev-ops\apache-hertzbeat-1.6.0-incubating-bin\plugin-lib\hertzbeat-plugin-2.0-SNAPSHOT.jar: 另一个程序正在使用此文件,进程无法访问。 java.lang.RuntimeException: java.nio.file.FileSystemException: D:\workspace\open\dev-ops\apache-hertzbeat-1.6.0-incubating-bin\plugin-lib\hertzbeat-plugin-2.0-SNAPSHOT.jar: 另一个程序正在使用此文件,进程无法访问。 at org.apache.hertzbeat.manager.service.impl.PluginServiceImpl.deletePlugins(PluginServiceImpl.java:95) at org.apache.hertzbeat.manager.controller.PluginController.deleteTags(PluginController.java:98) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:259) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:192) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:920) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:936) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:596) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at com.usthe.sureness.configuration.SurenessJakartaServletFilter.doFilter(SurenessJakartaServletFilter.java:102) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) at java.base/java.lang.Thread.run(Thread.java:842) Caused by: java.nio.file.FileSystemException: D:\workspace\open\dev-ops\apache-hertzbeat-1.6.0-incubating-bin\plugin-lib\hertzbeat-plugin-2.0-SNAPSHOT.jar: 另一个程序正在使用此文件,进程无法访问。 at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:92) at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103) at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108) at java.base/sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:275) at java.base/sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:105) at java.base/java.nio.file.Files.delete(Files.java:1152) at org.apache.commons.io.FileUtils.delete(FileUtils.java:1175) at org.apache.hertzbeat.manager.service.impl.PluginServiceImpl.deletePlugins(PluginServiceImpl.java:90) ... 62 common frames omitted

Anything else?

No response

zqr10159 commented 1 month ago

@LiuTianyou Please take a look.

pwallk commented 1 month ago

Beyond that, there are two questions:

  1. When two plug-ins (jar packages) have the same name, the old plug-in (jar package) will be overwritten.
  2. When two plug-ins have the same full class name, such as org.Apache.Hertzbeat.Plugin.Impl.DemoPluginImpl, despite the behavior is not the same, but throws an exception to stop adding and file upload is successful. This does not make sense because there is no guarantee that the classes in each plug-in (jar package) will be different. The common practice is to use a different classloader for each plug-in (jar package) to load, so that plug-ins are isolated. Of course, you can also consider using PF4j implementation.
LiuTianyou commented 1 month ago

Beyond that, there are two questions:

  1. When two plug-ins (jar packages) have the same name, the old plug-in (jar package) will be overwritten.
  2. When two plug-ins have the same full class name, such as org.Apache.Hertzbeat.Plugin.Impl.DemoPluginImpl, despite the behavior is not the same, but throws an exception to stop adding and file upload is successful. This does not make sense because there is no guarantee that the classes in each plug-in (jar package) will be different. The common practice is to use a different classloader for each plug-in (jar package) to load, so that plug-ins are isolated. Of course, you can also consider using PF4j implementation.

@pwallk Thank you for your suggestion. It is a good idea to use a mature framework. I will modify it to use pf4j later and fix the problem you mentioned.

tomsun28 commented 1 month ago

I thought of a point, but this is not necessary. Since we don't know what package the external plug-in introduces, it may causing jar conflicts and other problems. In the future, we can consider using classloading isolation to solve it.

LiuTianyou commented 1 month ago

@pwallk Hi, I have fixed the problem you mentioned. I tested it on Mac OS 13 and Windows 10 and it does not happen again. Could you help us test it again? Thank you very much. But there is one thing. If we use PF4J, it will not be compatible with previous versions. The plug-in packages that have been implemented before will not be usable. This needs to be discussed with the community before it can be decided.

pwallk commented 1 month ago

@LiuTianyou fixed

tomsun28 commented 1 month ago

The plug-in packages that have been implemented before will not be usable. This needs to be discussed with the community before it can be decided.

hi, the pr is great. suggest try not to introduce third-party packages.

LiuTianyou commented 1 month ago

@LiuTianyou fixed

Got it, thank you!

LiuTianyou commented 1 month ago

The plug-in packages that have been implemented before will not be usable. This needs to be discussed with the community before it can be decided.

hi, the pr is great. suggest try not to introduce third-party packages.

Got it!