This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new ac2487d55b fix(tars): avoid busy spin during proxy initialization
(#7099)
ac2487d55b is described below
commit ac2487d55b4ff9841b09e644f2e55f2f17c66948
Author: Liming Deng <[email protected]>
AuthorDate: Wed Sep 23 16:00:50 2026 +0800
fix(tars): avoid busy spin during proxy initialization (#7099)
* fix(tars): avoid busy spin during proxy initialization
* test(tars): enable module test suite
---------
Co-authored-by: aias00 <[email protected]>
---
.../shenyu-plugin-rpc/shenyu-plugin-tars/pom.xml | 11 ----
.../plugin/tars/cache/ApplicationConfigCache.java | 60 ++++++++++------------
.../tars/cache/ApplicationConfigCacheTest.java | 27 ++++++++++
3 files changed, 54 insertions(+), 44 deletions(-)
diff --git
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/pom.xml
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/pom.xml
index 25f0c005ce..87741342f2 100644
---
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/pom.xml
+++
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/pom.xml
@@ -62,15 +62,4 @@
</dependency>
</dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <skip>true</skip>
- </configuration>
- </plugin>
- </plugins>
- </build>
</project>
diff --git
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCache.java
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCache.java
index 1422da5d0c..6bd72c4896 100644
---
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCache.java
+++
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCache.java
@@ -186,27 +186,20 @@ public final class ApplicationConfigCache {
* @param metaData metaData
*/
public void initPrx(final MetaData metaData) {
- while (true) {
- Class<?> prxClass = prxClassCache.get(metaData.getPath());
- try {
- if (Objects.isNull(prxClass)) {
- // Spin's Attempt to Load
- tryLockedLoadMetaData(metaData);
- } else {
- if (Objects.nonNull(metaData.getContextPath()) &&
Objects.nonNull(refreshUpstreamCache.get(metaData.getContextPath()))) {
- refreshTarsInvokePrxList(metaData,
refreshUpstreamCache.get(metaData.getContextPath()));
- }
- break;
- }
- } catch (Exception e) {
- LOG.error("ShenyuTarsPluginInitializeException: init tars ref
ex:{}", e.getMessage());
- break;
+ try {
+ if (Objects.isNull(prxClassCache.get(metaData.getPath()))) {
+ lockedLoadMetaData(metaData);
+ }
+ if (Objects.nonNull(metaData.getContextPath()) &&
Objects.nonNull(refreshUpstreamCache.get(metaData.getContextPath()))) {
+ refreshTarsInvokePrxList(metaData,
refreshUpstreamCache.get(metaData.getContextPath()));
}
+ } catch (Exception e) {
+ LOG.error("ShenyuTarsPluginInitializeException: init tars ref
ex:{}", e.getMessage());
}
}
-
+
/**
- * Try to load once, if it fails, it will give up.<br>
+ * Load metadata while holding the initialization lock.<br>
* add class cache to {@link #prxClassCache}.<br>
* add method params cache to {@link #prxParamCache}.<br>
* add paths cache to {@link #ctxPathCache}.<br>
@@ -215,23 +208,24 @@ public final class ApplicationConfigCache {
* @throws ClassNotFoundException meta data class definition not found
* @see ReentrantLock
*/
- private void tryLockedLoadMetaData(final MetaData metaData) throws
ClassNotFoundException {
- Objects.requireNonNull(LOCK);
- if (LOCK.tryLock()) {
- try {
- if (StringUtils.isEmpty(metaData.getRpcExt())) {
- throw new
ShenyuTarsPluginException("ShenyuTarsPluginInitializeException: can't init prx
with empty ext string");
- }
- Class<?> prxClazz = buildClassDefinition(metaData);
- prxClassCache.put(metaData.getPath(), prxClazz);
- List<MetaData> paths =
ctxPathCache.getOrDefault(metaData.getContextPath(), new ArrayList<>());
- if (!IterableUtils.matchesAny(paths, p ->
p.getPath().equals(metaData.getPath()))) {
- paths.add(metaData);
- }
- ctxPathCache.put(metaData.getContextPath(), paths);
- } finally {
- LOCK.unlock();
+ private void lockedLoadMetaData(final MetaData metaData) throws
ClassNotFoundException {
+ LOCK.lock();
+ try {
+ if (prxClassCache.containsKey(metaData.getPath())) {
+ return;
+ }
+ if (StringUtils.isEmpty(metaData.getRpcExt())) {
+ throw new
ShenyuTarsPluginException("ShenyuTarsPluginInitializeException: can't init prx
with empty ext string");
+ }
+ Class<?> prxClazz = buildClassDefinition(metaData);
+ prxClassCache.put(metaData.getPath(), prxClazz);
+ List<MetaData> paths =
ctxPathCache.getOrDefault(metaData.getContextPath(), new ArrayList<>());
+ if (!IterableUtils.matchesAny(paths, p ->
p.getPath().equals(metaData.getPath()))) {
+ paths.add(metaData);
}
+ ctxPathCache.put(metaData.getContextPath(), paths);
+ } finally {
+ LOCK.unlock();
}
}
diff --git
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCacheTest.java
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCacheTest.java
index cbf228627e..eadccbb998 100644
---
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCacheTest.java
+++
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/cache/ApplicationConfigCacheTest.java
@@ -30,13 +30,16 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
+import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.locks.ReentrantLock;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -121,6 +124,30 @@ public final class ApplicationConfigCacheTest {
});
}
+ @Test
+ public void testInitPrxWaitsForInitializationLock() throws Exception {
+ final Field lockField =
ApplicationConfigCache.class.getDeclaredField("LOCK");
+ lockField.setAccessible(true);
+ final ReentrantLock lock = (ReentrantLock) lockField.get(null);
+ final MetaData metaData = new MetaData("id", "appName", "contextPath",
"waitingPath",
+ RpcTypeEnum.TARS.getName(), "serviceName", "methodName",
"parameterTypes",
+ null, false, Constants.SYS_DEFAULT_NAMESPACE_ID);
+ final Thread initThread = new Thread(() ->
applicationConfigCacheUnderTest.initPrx(metaData));
+
+ lock.lock();
+ try {
+ initThread.start();
+ for (int i = 0; i < 100 && !lock.hasQueuedThread(initThread); i++)
{
+ Thread.sleep(10L);
+ }
+ assertTrue(lock.hasQueuedThread(initThread));
+ } finally {
+ lock.unlock();
+ }
+ initThread.join(1000L);
+ assertFalse(initThread.isAlive());
+ }
+
@Test
public void testInitPrx() {
final MetaData metaData = new MetaData("id", "127.0.0.1:8080",
"contextPath",