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));