This is an automated email from the ASF dual-hosted git repository.

zihaoxiang pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 8ebc6f3b4d [Fix-17469]Fix threadLocal will not clean if exception 
occur in LoginHandlerInterceptor (#17474)
8ebc6f3b4d is described below

commit 8ebc6f3b4d7e0fa36bea5f57d435ace7657d6fab
Author: njnu-seafish <[email protected]>
AuthorDate: Mon Sep 8 16:36:13 2025 +0800

    [Fix-17469]Fix threadLocal will not clean if exception occur in 
LoginHandlerInterceptor (#17474)
---
 .../api/interceptor/LoginHandlerInterceptor.java   | 11 ++++--
 .../common/thread/ThreadLocalContext.java          | 42 +++++++++++++++++++---
 .../dolphinscheduler/common/utils/DateUtils.java   |  6 ++--
 .../common/utils/DateUtilsTest.java                |  8 ++---
 4 files changed, 54 insertions(+), 13 deletions(-)

diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LoginHandlerInterceptor.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LoginHandlerInterceptor.java
index 49eacaa59c..e4d292b2cc 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LoginHandlerInterceptor.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LoginHandlerInterceptor.java
@@ -91,7 +91,7 @@ public class LoginHandlerInterceptor implements 
HandlerInterceptor {
             return false;
         }
         request.setAttribute(Constants.SESSION_USER, user);
-        ThreadLocalContext.getTimezoneThreadLocal().set(user.getTimeZone());
+        ThreadLocalContext.setTimezone(user.getTimeZone());
         return true;
     }
 
@@ -100,7 +100,6 @@ public class LoginHandlerInterceptor implements 
HandlerInterceptor {
                            HttpServletResponse response,
                            Object handler,
                            ModelAndView modelAndView) {
-        ThreadLocalContext.getTimezoneThreadLocal().remove();
 
         int code = response.getStatus();
         if (code >= 200 && code < 300) {
@@ -113,4 +112,12 @@ public class LoginHandlerInterceptor implements 
HandlerInterceptor {
             ApiServerMetrics.incApiResponse5xxCount();
         }
     }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request,
+                                HttpServletResponse response,
+                                Object handler,
+                                Exception ex) {
+        ThreadLocalContext.removeTimezone();
+    }
 }
diff --git 
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/thread/ThreadLocalContext.java
 
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/thread/ThreadLocalContext.java
index 9d523d815a..14365c9903 100644
--- 
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/thread/ThreadLocalContext.java
+++ 
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/thread/ThreadLocalContext.java
@@ -18,13 +18,47 @@
 package org.apache.dolphinscheduler.common.thread;
 
 /**
- * thread local context
+ * A utility class to manage timezone context using ThreadLocal.
+ * This allows each thread to have its own timezone value, which is useful in
+ * multi-threaded environments such as web applications where each request
+ * may need to operate in a different timezone.
+ *
+ * Note: Always call {@link #removeTimezone()} at the end of a request or task
+ * to prevent memory leaks and context pollution in thread pool environments.
  */
 public class ThreadLocalContext {
 
-    public static final ThreadLocal<String> timezoneThreadLocal = new 
ThreadLocal<>();
+    /**
+     * ThreadLocal variable to hold the timezone string for the current thread.
+     * Each thread will have its own copy of the timezone value.
+     */
+    private static final ThreadLocal<String> TIMEZONE_THREAD_LOCAL = new 
ThreadLocal<>();
+
+    /**
+     * Sets the timezone for the current thread.
+     *
+     * @param timezone the timezone ID (e.g., "UTC", "Asia/Shanghai", 
"America/New_York")
+     */
+    public static void setTimezone(String timezone) {
+        TIMEZONE_THREAD_LOCAL.set(timezone);
+    }
+
+    /**
+     * Retrieves the timezone for the current thread.
+     *
+     * @return the timezone string set for the current thread, or null if not 
set
+     */
+    public static String getTimezone() {
+        return TIMEZONE_THREAD_LOCAL.get();
+    }
 
-    public static ThreadLocal<String> getTimezoneThreadLocal() {
-        return timezoneThreadLocal;
+    /**
+     * Removes the timezone value for the current thread.
+     * This method should be called to clean up the thread-local value, 
especially
+     * when using thread pools (e.g., in web servers), to prevent memory leaks
+     * and unintended data leakage between requests.
+     */
+    public static void removeTimezone() {
+        TIMEZONE_THREAD_LOCAL.remove();
     }
 }
diff --git 
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/DateUtils.java
 
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/DateUtils.java
index 18370ae378..50a5afcf37 100644
--- 
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/DateUtils.java
+++ 
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/DateUtils.java
@@ -62,13 +62,13 @@ public final class DateUtils {
      * @return local datetime
      */
     private static LocalDateTime date2LocalDateTime(Date date) {
-        String timezone = ThreadLocalContext.getTimezoneThreadLocal().get();
+        String timezone = ThreadLocalContext.getTimezone();
         ZoneId zoneId = StringUtils.isNotEmpty(timezone) ? ZoneId.of(timezone) 
: ZoneId.systemDefault();
         return date2LocalDateTime(date, zoneId);
     }
 
     public static String getTimezone() {
-        String timezone = ThreadLocalContext.getTimezoneThreadLocal().get();
+        String timezone = ThreadLocalContext.getTimezone();
         return StringUtils.isNotEmpty(timezone) ? timezone : 
ZoneId.systemDefault().getId();
     }
 
@@ -90,7 +90,7 @@ public final class DateUtils {
      * @return date
      */
     private static Date localDateTime2Date(LocalDateTime localDateTime) {
-        String timezone = ThreadLocalContext.getTimezoneThreadLocal().get();
+        String timezone = ThreadLocalContext.getTimezone();
         ZoneId zoneId = StringUtils.isNotEmpty(timezone) ? ZoneId.of(timezone) 
: ZoneId.systemDefault();
         return localDateTime2Date(localDateTime, zoneId);
     }
diff --git 
a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/DateUtilsTest.java
 
b/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/DateUtilsTest.java
index dc07c1cdaa..e05e350098 100644
--- 
a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/DateUtilsTest.java
+++ 
b/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/DateUtilsTest.java
@@ -37,12 +37,12 @@ public class DateUtilsTest {
 
     @BeforeEach
     public void before() {
-        ThreadLocalContext.getTimezoneThreadLocal().remove();
+        ThreadLocalContext.removeTimezone();
     }
 
     @AfterEach
     public void after() {
-        ThreadLocalContext.getTimezoneThreadLocal().remove();
+        ThreadLocalContext.removeTimezone();
     }
 
     @Test
@@ -242,11 +242,11 @@ public class DateUtilsTest {
     public void testTimezone() {
 
         String time = "2019-01-28 00:00:00";
-        ThreadLocalContext.timezoneThreadLocal.set("UTC");
+        ThreadLocalContext.setTimezone("UTC");
         Date utcDate = DateUtils.stringToDate(time);
         Assertions.assertEquals(time, DateUtils.dateToString(utcDate));
 
-        ThreadLocalContext.timezoneThreadLocal.set("Asia/Shanghai");
+        ThreadLocalContext.setTimezone("Asia/Shanghai");
         Date shanghaiDate = DateUtils.stringToDate(time);
         Assertions.assertEquals(time, DateUtils.dateToString(shanghaiDate));
 

Reply via email to