Skip to content

Commit 8ebc6f3

Browse files
authored
[Fix-17469]Fix threadLocal will not clean if exception occur in LoginHandlerInterceptor (#17474)
1 parent 4ec7c4b commit 8ebc6f3

4 files changed

Lines changed: 54 additions & 13 deletions

File tree

dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LoginHandlerInterceptor.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
9191
return false;
9292
}
9393
request.setAttribute(Constants.SESSION_USER, user);
94-
ThreadLocalContext.getTimezoneThreadLocal().set(user.getTimeZone());
94+
ThreadLocalContext.setTimezone(user.getTimeZone());
9595
return true;
9696
}
9797

@@ -100,7 +100,6 @@ public void postHandle(HttpServletRequest request,
100100
HttpServletResponse response,
101101
Object handler,
102102
ModelAndView modelAndView) {
103-
ThreadLocalContext.getTimezoneThreadLocal().remove();
104103

105104
int code = response.getStatus();
106105
if (code >= 200 && code < 300) {
@@ -113,4 +112,12 @@ public void postHandle(HttpServletRequest request,
113112
ApiServerMetrics.incApiResponse5xxCount();
114113
}
115114
}
115+
116+
@Override
117+
public void afterCompletion(HttpServletRequest request,
118+
HttpServletResponse response,
119+
Object handler,
120+
Exception ex) {
121+
ThreadLocalContext.removeTimezone();
122+
}
116123
}

dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/thread/ThreadLocalContext.java

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,47 @@
1818
package org.apache.dolphinscheduler.common.thread;
1919

2020
/**
21-
* thread local context
21+
* A utility class to manage timezone context using ThreadLocal.
22+
* This allows each thread to have its own timezone value, which is useful in
23+
* multi-threaded environments such as web applications where each request
24+
* may need to operate in a different timezone.
25+
*
26+
* Note: Always call {@link #removeTimezone()} at the end of a request or task
27+
* to prevent memory leaks and context pollution in thread pool environments.
2228
*/
2329
public class ThreadLocalContext {
2430

25-
public static final ThreadLocal<String> timezoneThreadLocal = new ThreadLocal<>();
31+
/**
32+
* ThreadLocal variable to hold the timezone string for the current thread.
33+
* Each thread will have its own copy of the timezone value.
34+
*/
35+
private static final ThreadLocal<String> TIMEZONE_THREAD_LOCAL = new ThreadLocal<>();
36+
37+
/**
38+
* Sets the timezone for the current thread.
39+
*
40+
* @param timezone the timezone ID (e.g., "UTC", "Asia/Shanghai", "America/New_York")
41+
*/
42+
public static void setTimezone(String timezone) {
43+
TIMEZONE_THREAD_LOCAL.set(timezone);
44+
}
45+
46+
/**
47+
* Retrieves the timezone for the current thread.
48+
*
49+
* @return the timezone string set for the current thread, or null if not set
50+
*/
51+
public static String getTimezone() {
52+
return TIMEZONE_THREAD_LOCAL.get();
53+
}
2654

27-
public static ThreadLocal<String> getTimezoneThreadLocal() {
28-
return timezoneThreadLocal;
55+
/**
56+
* Removes the timezone value for the current thread.
57+
* This method should be called to clean up the thread-local value, especially
58+
* when using thread pools (e.g., in web servers), to prevent memory leaks
59+
* and unintended data leakage between requests.
60+
*/
61+
public static void removeTimezone() {
62+
TIMEZONE_THREAD_LOCAL.remove();
2963
}
3064
}

dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/DateUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ private DateUtils() {
6262
* @return local datetime
6363
*/
6464
private static LocalDateTime date2LocalDateTime(Date date) {
65-
String timezone = ThreadLocalContext.getTimezoneThreadLocal().get();
65+
String timezone = ThreadLocalContext.getTimezone();
6666
ZoneId zoneId = StringUtils.isNotEmpty(timezone) ? ZoneId.of(timezone) : ZoneId.systemDefault();
6767
return date2LocalDateTime(date, zoneId);
6868
}
6969

7070
public static String getTimezone() {
71-
String timezone = ThreadLocalContext.getTimezoneThreadLocal().get();
71+
String timezone = ThreadLocalContext.getTimezone();
7272
return StringUtils.isNotEmpty(timezone) ? timezone : ZoneId.systemDefault().getId();
7373
}
7474

@@ -90,7 +90,7 @@ private static LocalDateTime date2LocalDateTime(Date date, ZoneId zoneId) {
9090
* @return date
9191
*/
9292
private static Date localDateTime2Date(LocalDateTime localDateTime) {
93-
String timezone = ThreadLocalContext.getTimezoneThreadLocal().get();
93+
String timezone = ThreadLocalContext.getTimezone();
9494
ZoneId zoneId = StringUtils.isNotEmpty(timezone) ? ZoneId.of(timezone) : ZoneId.systemDefault();
9595
return localDateTime2Date(localDateTime, zoneId);
9696
}

dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/DateUtilsTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ public class DateUtilsTest {
3737

3838
@BeforeEach
3939
public void before() {
40-
ThreadLocalContext.getTimezoneThreadLocal().remove();
40+
ThreadLocalContext.removeTimezone();
4141
}
4242

4343
@AfterEach
4444
public void after() {
45-
ThreadLocalContext.getTimezoneThreadLocal().remove();
45+
ThreadLocalContext.removeTimezone();
4646
}
4747

4848
@Test
@@ -242,11 +242,11 @@ public void testGetTimezone() {
242242
public void testTimezone() {
243243

244244
String time = "2019-01-28 00:00:00";
245-
ThreadLocalContext.timezoneThreadLocal.set("UTC");
245+
ThreadLocalContext.setTimezone("UTC");
246246
Date utcDate = DateUtils.stringToDate(time);
247247
Assertions.assertEquals(time, DateUtils.dateToString(utcDate));
248248

249-
ThreadLocalContext.timezoneThreadLocal.set("Asia/Shanghai");
249+
ThreadLocalContext.setTimezone("Asia/Shanghai");
250250
Date shanghaiDate = DateUtils.stringToDate(time);
251251
Assertions.assertEquals(time, DateUtils.dateToString(shanghaiDate));
252252

0 commit comments

Comments
 (0)