You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2021/03/31 09:14:03 UTC
[servicecomb-java-chassis] branch master updated: [SCB-2249] check
invocation timeout support strategies (#2333)
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
The following commit(s) were added to refs/heads/master by this push:
new 90cd821 [SCB-2249] check invocation timeout support strategies (#2333)
90cd821 is described below
commit 90cd8212242c311363103c76f35d5a618f2d6dfc
Author: wujimin <wu...@huawei.com>
AuthorDate: Wed Mar 31 17:13:55 2021 +0800
[SCB-2249] check invocation timeout support strategies (#2333)
---
.../impl/ConfigurableDatetimeAccessItem.java | 2 +-
.../accessLog/core/AccessLogGeneratorTest.java | 3 +-
.../element/impl/DatetimeConfigurableItemTest.java | 2 +-
.../common/rest/AbstractRestInvocation.java | 2 +-
.../java/org/apache/servicecomb/core/Const.java | 6 -
.../core/invocation/InvocationStageTrace.java | 12 +-
.../invocation/InvocationTimeoutBootListener.java | 105 ++++++------------
.../core/invocation/InvocationTimeoutStrategy.java | 76 +++++++++++++
.../invocation/timeout/PassingTimeStrategy.java | 100 +++++++++++++++++
.../invocation/timeout/ProcessingTimeStrategy.java | 123 +++++++++++++++++++++
.../timeout/PassingTimeStrategyTest.java | 78 +++++++++++++
.../timeout/ProcessingTimeStrategyTest.java | 89 +++++++++++++++
.../src/main/resources/microservice.yaml | 20 ++--
.../src/main/resources/microservice.yaml | 4 +-
.../client/TestSpringMVCCommonSchemaInterface.java | 7 +-
.../src/main/resources/microservice.yaml | 5 +
.../src/main/resources/microservice.yaml | 4 +
.../servicecomb/config/BootStrapProperties.java | 28 +++--
.../registry/config/AbstractPropertiesLoader.java | 1 -
.../test/scaffolding/time}/MockClock.java | 22 ++--
.../test/scaffolding/{ => time}/MockTicker.java | 32 ++----
.../{MockTicker.java => time/MockValues.java} | 29 ++---
.../loadbalance/TestServiceCombServerStats.java | 11 +-
.../registry/lightweight/StoreServiceTest.java | 6 +-
.../instance/TestInstanceCacheCheckerMock.java | 10 +-
.../TestInstanceCacheCheckerWithoutMock.java | 5 +-
26 files changed, 606 insertions(+), 176 deletions(-)
diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ConfigurableDatetimeAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ConfigurableDatetimeAccessItem.java
index 31a38d7..c522927 100644
--- a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ConfigurableDatetimeAccessItem.java
+++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ConfigurableDatetimeAccessItem.java
@@ -94,7 +94,7 @@ public class ConfigurableDatetimeAccessItem implements AccessLogItem<RoutingCont
long milliDuration = (finishEvent.getInvocation().getInvocationStageTrace().getStartSend() -
finishEvent.getInvocation().getInvocationStageTrace().getStart()) / 1000_000;
doAppendFormattedItem(
- finishEvent.getInvocation().getInvocationStageTrace().getStartCurrentTime() + milliDuration, builder);
+ finishEvent.getInvocation().getInvocationStageTrace().getStartTimeMillis() + milliDuration, builder);
}
private void doAppendFormattedItem(long milliStartTime, StringBuilder builder) {
diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/AccessLogGeneratorTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/AccessLogGeneratorTest.java
index ca219df..bd0e880 100644
--- a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/AccessLogGeneratorTest.java
+++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/AccessLogGeneratorTest.java
@@ -34,7 +34,6 @@ import org.apache.servicecomb.core.definition.OperationMeta;
import org.apache.servicecomb.core.event.InvocationFinishEvent;
import org.apache.servicecomb.core.event.ServerAccessLogEvent;
import org.apache.servicecomb.core.invocation.InvocationStageTrace;
-
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
@@ -87,7 +86,7 @@ public class AccessLogGeneratorTest {
when(stageTrace.getStartSend()).thenReturn(0L);
when(stageTrace.getStart()).thenReturn(0L);
when(stageTrace.getFinish()).thenReturn(0L);
- when(stageTrace.getStartCurrentTime()).thenReturn(startMillisecond);
+ when(stageTrace.getStartTimeMillis()).thenReturn(startMillisecond);
when(invocation.getOperationMeta()).thenReturn(operationMeta);
when(invocation.getInvocationStageTrace()).thenReturn(stageTrace);
diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DatetimeConfigurableItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DatetimeConfigurableItemTest.java
index ef5b06d..c46e803 100644
--- a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DatetimeConfigurableItemTest.java
+++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DatetimeConfigurableItemTest.java
@@ -56,7 +56,7 @@ public class DatetimeConfigurableItemTest {
when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace);
when(invocationStageTrace.getStartSend()).thenReturn(0L);
when(invocationStageTrace.getStart()).thenReturn(0L);
- when(invocationStageTrace.getStartCurrentTime()).thenReturn(START_MILLISECOND);
+ when(invocationStageTrace.getStartTimeMillis()).thenReturn(START_MILLISECOND);
accessLogEvent = new ServerAccessLogEvent();
accessLogEvent.setMilliStartTime(START_MILLISECOND);
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java
index 5041d6c..1b638a9 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java
@@ -133,7 +133,7 @@ public abstract class AbstractRestInvocation {
sendFailResponse(e);
return;
}
-
+
invocation.onStart(requestEx, start);
invocation.getInvocationStageTrace().startSchedule();
OperationMeta operationMeta = restOperationMeta.getOperationMeta();
diff --git a/core/src/main/java/org/apache/servicecomb/core/Const.java b/core/src/main/java/org/apache/servicecomb/core/Const.java
index e4940aa..fc90ac0 100644
--- a/core/src/main/java/org/apache/servicecomb/core/Const.java
+++ b/core/src/main/java/org/apache/servicecomb/core/Const.java
@@ -25,12 +25,6 @@ public final class Const {
public static final String CSE_CONTEXT = "x-cse-context";
- public static final String CONTEXT_TIME_ELAPSED = "x-scb-time";
-
- public static final String CONTEXT_TIMED_OUT = "x-scb-timed-out";
-
- public static final String CONTEXT_TIME_CURRENT = "x-scb-time-current";
-
public static final String RESTFUL = "rest";
public static final String HIGHWAY = "highway";
diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java
index b5a81f1..396a478 100644
--- a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java
+++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java
@@ -88,7 +88,7 @@ public class InvocationStageTrace {
private Invocation invocation;
// current time for start invocation
- private long startCurrentTime;
+ private long startTimeMillis;
private long start;
@@ -139,7 +139,7 @@ public class InvocationStageTrace {
public void start(long start) {
// remember the current time to start invocation
- this.startCurrentTime = System.currentTimeMillis();
+ this.startTimeMillis = System.currentTimeMillis();
this.start = start;
}
@@ -147,12 +147,12 @@ public class InvocationStageTrace {
return start;
}
- public long getStartCurrentTime() {
- return startCurrentTime;
+ public long getStartTimeMillis() {
+ return startTimeMillis;
}
- public InvocationStageTrace setStartCurrentTime(long startCurrentTime) {
- this.startCurrentTime = startCurrentTime;
+ public InvocationStageTrace setStartTimeMillis(long startTimeMillis) {
+ this.startTimeMillis = startTimeMillis;
return this;
}
diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutBootListener.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutBootListener.java
index 86fed19..5c8ac67 100644
--- a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutBootListener.java
+++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutBootListener.java
@@ -17,12 +17,8 @@
package org.apache.servicecomb.core.invocation;
-import static javax.ws.rs.core.Response.Status.REQUEST_TIMEOUT;
+import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.servicecomb.core.BootListener;
-import org.apache.servicecomb.core.Const;
-import org.apache.servicecomb.core.Invocation;
import org.apache.servicecomb.core.event.InvocationBusinessFinishEvent;
import org.apache.servicecomb.core.event.InvocationBusinessMethodStartEvent;
import org.apache.servicecomb.core.event.InvocationHandlersStartEvent;
@@ -30,122 +26,83 @@ import org.apache.servicecomb.core.event.InvocationRunInExecutorStartEvent;
import org.apache.servicecomb.core.event.InvocationStartEvent;
import org.apache.servicecomb.core.event.InvocationStartSendRequestEvent;
import org.apache.servicecomb.core.event.InvocationTimeoutCheckEvent;
-import org.apache.servicecomb.core.exception.ExceptionCodes;
+import org.apache.servicecomb.core.invocation.timeout.PassingTimeStrategy;
import org.apache.servicecomb.foundation.common.event.EnableExceptionPropagation;
-import org.apache.servicecomb.foundation.common.event.EventManager;
-import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
+import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
-import com.netflix.config.DynamicPropertyFactory;
@SuppressWarnings({"UnstableApiUsage", "unused"})
@Component
-public class InvocationTimeoutBootListener implements BootListener {
+public class InvocationTimeoutBootListener {
private static final Logger LOGGER = LoggerFactory.getLogger(InvocationTimeoutBootListener.class);
- public static final String ENABLE_TIMEOUT_CHECK = "servicecomb.invocation.enableTimeoutCheck";
+ public static final String PREFIX = "servicecomb.invocation.timeout.check";
- public static boolean timeoutCheckEnabled() {
- return DynamicPropertyFactory.getInstance().getBooleanProperty(ENABLE_TIMEOUT_CHECK, true).get();
- }
+ public static final String STRATEGY = PREFIX + ".strategy";
- @Override
- public void onAfterTransport(BootEvent event) {
- if (timeoutCheckEnabled()) {
- EventManager.getEventBus().register(this);
- }
- }
+ public static final String ENABLED = PREFIX + ".enabled";
- @Subscribe
- public void onInvocationStartEvent(InvocationStartEvent event) {
- Invocation invocation = event.getInvocation();
-
- // not initialized
- // 1. when first time received request
- // 2. when first time send request not a user thread
- // initialized
- // 1. send request in the progress of processing request
- if (invocation.getLocalContext(Const.CONTEXT_TIME_CURRENT) == null) {
- invocation.addLocalContext(Const.CONTEXT_TIME_CURRENT, invocation.getInvocationStageTrace().getStart());
- }
+ private final InvocationTimeoutStrategy strategy;
- if (invocation.getLocalContext(Const.CONTEXT_TIME_ELAPSED) == null) {
- String elapsed = invocation.getContext(Const.CONTEXT_TIME_ELAPSED);
- if (StringUtils.isEmpty(elapsed)) {
- invocation.addLocalContext(Const.CONTEXT_TIME_ELAPSED, 0L);
- return;
- }
-
- try {
- invocation.addLocalContext(Const.CONTEXT_TIME_ELAPSED, Long.parseLong(elapsed));
- } catch (NumberFormatException e) {
- LOGGER.error("Not expected number format exception, attacker?");
- invocation.addLocalContext(Const.CONTEXT_TIME_ELAPSED, 0L);
- }
+ public InvocationTimeoutBootListener(EventBus eventBus, List<InvocationTimeoutStrategy> strategies,
+ Environment environment) {
+ if (!environment.getProperty(ENABLED, boolean.class, false)) {
+ strategy = null;
+ return;
}
+
+ String strategyName = environment.getProperty(STRATEGY, PassingTimeStrategy.NAME);
+ // if strategyName is wrong, then just throw exception
+ strategy = strategies.stream()
+ .filter(invocationTimeoutStrategy -> strategyName.equals(invocationTimeoutStrategy.name()))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("can not find InvocationTimeoutStrategy, name=" + strategyName));
+ eventBus.register(this);
}
@Subscribe
@EnableExceptionPropagation
public void onInvocationTimeoutCheckEvent(InvocationTimeoutCheckEvent event) {
- ensureInvocationNotTimeout(event.getInvocation());
- }
-
- /**
- * check if invocation is timeout.
- *
- * @throws InvocationException if timeout, throw an exception. Will not throw exception twice if this method called
- * after timeout.
- */
- private void ensureInvocationNotTimeout(Invocation invocation) {
- if (invocation.getOperationMeta().getConfig().getNanoInvocationTimeout() > 0 && calculateElapsedTime(invocation) >
- invocation.getOperationMeta().getConfig().getNanoInvocationTimeout()) {
- if (invocation.getLocalContext(Const.CONTEXT_TIMED_OUT) != null) {
- // already timed out, do not throw exception again
- return;
- }
- invocation.addLocalContext(Const.CONTEXT_TIMED_OUT, true);
- throw new InvocationException(REQUEST_TIMEOUT, ExceptionCodes.INVOCATION_TIMEOUT, "Invocation Timeout.");
- }
+ strategy.checkTimeout(event.getInvocation());
}
- private long calculateElapsedTime(Invocation invocation) {
- return System.nanoTime() - (long) invocation.getLocalContext(Const.CONTEXT_TIME_CURRENT)
- + (long) invocation.getLocalContext(Const.CONTEXT_TIME_ELAPSED);
+ @Subscribe
+ public void onInvocationStartEvent(InvocationStartEvent event) {
+ strategy.start(event.getInvocation());
}
@Subscribe
@EnableExceptionPropagation
public void onInvocationRunInExecutorStartEvent(InvocationRunInExecutorStartEvent event) {
- ensureInvocationNotTimeout(event.getInvocation());
+ strategy.startRunInExecutor(event.getInvocation());
}
@Subscribe
@EnableExceptionPropagation
public void onInvocationHandlersStartEvent(InvocationHandlersStartEvent event) {
- ensureInvocationNotTimeout(event.getInvocation());
+ strategy.startHandlers(event.getInvocation());
}
@Subscribe
@EnableExceptionPropagation
public void onInvocationBusinessMethodStartEvent(InvocationBusinessMethodStartEvent event) {
- ensureInvocationNotTimeout(event.getInvocation());
+ strategy.startBusinessMethod(event.getInvocation());
}
@Subscribe
@EnableExceptionPropagation
public void onInvocationBusinessFinishEvent(InvocationBusinessFinishEvent event) {
- ensureInvocationNotTimeout(event.getInvocation());
+ strategy.finishBusinessMethod(event.getInvocation());
}
@Subscribe
@EnableExceptionPropagation
public void onInvocationStartSendRequestEvent(InvocationStartSendRequestEvent event) {
- Invocation invocation = event.getInvocation();
- ensureInvocationNotTimeout(invocation);
- invocation.addContext(Const.CONTEXT_TIME_ELAPSED, Long.toString(calculateElapsedTime(invocation)));
+ strategy.beforeSendRequest(event.getInvocation());
}
}
diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutStrategy.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutStrategy.java
new file mode 100644
index 0000000..5e31c59
--- /dev/null
+++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutStrategy.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.core.invocation;
+
+import static javax.ws.rs.core.Response.Status.REQUEST_TIMEOUT;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.exception.ExceptionCodes;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+
+public interface InvocationTimeoutStrategy {
+ // indicate whether invocation already timeout inside a process
+ // null is not timeout
+ // other value is timeout
+ String CHAIN_ALREADY_TIMED_OUT = "x-scb-chain-timed-out";
+
+ String name();
+
+ void start(Invocation invocation);
+
+ default void startRunInExecutor(Invocation invocation) {
+ checkTimeout(invocation);
+ }
+
+ default void startHandlers(Invocation invocation) {
+ checkTimeout(invocation);
+ }
+
+ default void startBusinessMethod(Invocation invocation) {
+ checkTimeout(invocation);
+ }
+
+ default void finishBusinessMethod(Invocation invocation) {
+ checkTimeout(invocation);
+ }
+
+ default void beforeSendRequest(Invocation invocation) {
+ checkTimeout(invocation);
+ }
+
+ default void checkTimeout(Invocation invocation) {
+ long nanoInvocationTimeout = invocation.getOperationMeta().getConfig().getNanoInvocationTimeout();
+ if (nanoInvocationTimeout <= 0 || alreadyTimeout(invocation)) {
+ return;
+ }
+
+ long nanoTime = calculateElapsedNanoTime(invocation);
+ if (nanoTime <= nanoInvocationTimeout) {
+ return;
+ }
+
+ invocation.addLocalContext(CHAIN_ALREADY_TIMED_OUT, true);
+ throw new InvocationException(REQUEST_TIMEOUT, ExceptionCodes.INVOCATION_TIMEOUT, "Invocation Timeout.");
+ }
+
+ default boolean alreadyTimeout(Invocation invocation) {
+ return invocation.getLocalContext(CHAIN_ALREADY_TIMED_OUT) != null;
+ }
+
+ long calculateElapsedNanoTime(Invocation invocation);
+}
diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategy.java b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategy.java
new file mode 100644
index 0000000..4e9ce74
--- /dev/null
+++ b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategy.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.core.invocation.timeout;
+
+import java.time.Clock;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.invocation.InvocationTimeoutStrategy;
+import org.springframework.stereotype.Component;
+
+/**
+ * <pre>
+ * based on time synchronization
+ * any time to calculate timeout: now - start time of invocation chain
+ *
+ * consumer: c
+ * producer: p
+ * ---------------------------------------------------------------
+ * | process 2 |
+ * | c-send(T5) c-send(T8) |
+ * | ↑ ↑ |
+ * | p-start(T3) → c-start(T4) → p-operation(T6) → c-start(T7)|
+ * -----↑--------------------------------------------------------
+ * ↑
+ * -----↑-----------------
+ * | ↑ process 1 |
+ * | c-send(T2) |
+ * | ↑ |
+ * | c-start(T1) |
+ * ------------------------
+ *
+ * T2 timeout: T2 - T1
+ * T3 timeout: T3 - T1
+ * T4 timeout: T4 - T1
+ * ......
+ * </pre>
+ */
+@Component
+public class PassingTimeStrategy implements InvocationTimeoutStrategy {
+ public static final String NAME = "passing-time";
+
+ // milliseconds
+ // depend on time synchronization
+ // transfer between processes
+ public static final String CHAIN_START_TIME = "x-scb-chain-start";
+
+ private Clock clock = Clock.systemDefaultZone();
+
+ public PassingTimeStrategy setClock(Clock clock) {
+ this.clock = clock;
+ return this;
+ }
+
+ @Override
+ public String name() {
+ return NAME;
+ }
+
+ @Override
+ public void start(Invocation invocation) {
+ if (invocation.getLocalContext(CHAIN_START_TIME) != null) {
+ return;
+ }
+
+ long startTimeMillis = invocation.getInvocationStageTrace().getStartTimeMillis();
+ String contextChainStartTime = invocation.getContext(CHAIN_START_TIME);
+ if (StringUtils.isEmpty(contextChainStartTime)) {
+ invocation.addContext(CHAIN_START_TIME, String.valueOf(startTimeMillis));
+ invocation.addLocalContext(CHAIN_START_TIME, startTimeMillis);
+ return;
+ }
+
+ long chainStartTime = NumberUtils.toLong(contextChainStartTime, startTimeMillis);
+ invocation.addLocalContext(CHAIN_START_TIME, chainStartTime);
+ }
+
+ @Override
+ public long calculateElapsedNanoTime(Invocation invocation) {
+ long passingTimeMillis = clock.millis() - invocation.<Long>getLocalContext(CHAIN_START_TIME);
+ return TimeUnit.MILLISECONDS.toNanos(passingTimeMillis);
+ }
+}
diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategy.java b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategy.java
new file mode 100644
index 0000000..8fbed64
--- /dev/null
+++ b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategy.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.core.invocation.timeout;
+
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.invocation.InvocationTimeoutStrategy;
+import org.springframework.stereotype.Component;
+
+import com.google.common.base.Ticker;
+
+/**
+ * <pre>
+ * Cumulative Processing Time
+ * not depend on time synchronization
+ * but lost network and framework outside of servicecomb processing time
+ *
+ * consumer: c
+ * producer: p
+ * ---------------------------------------------------------------
+ * | process 2 |
+ * | c-send(T5) c-send(T8) |
+ * | ↑ ↑ |
+ * | p-start(T3) → c-start(T4) → p-operation(T6) → c-start(T7)|
+ * -----↑--------------------------------------------------------
+ * ↑
+ * -----↑-----------------
+ * | ↑ process 1 |
+ * | c-send(T2) |
+ * | ↑ |
+ * | c-start(T1) |
+ * ------------------------
+ *
+ * T2 timeout: T2 - T1
+ * T3 timeout: (T2 - T1) + (T3 - T3)
+ * T4 timeout: (T2 - T1) + (T4 - T3)
+ * T5 timeout: (T2 - T1) + (T5 - T3)
+ * T6 timeout: (T2 - T1) + (T6 - T3)
+ * T7 timeout: (T2 - T1) + (T7 - T3)
+ * T8 timeout: (T2 - T1) + (T8 - T3)
+ * ......
+ * </pre>
+ */
+@Component
+public class ProcessingTimeStrategy implements InvocationTimeoutStrategy {
+ public static final String NAME = "processing-time";
+
+ // nanoseconds
+ // used inside one process
+ // not depend on time synchronization
+ public static final String CHAIN_START_TIME = "x-scb-process-chain-start";
+
+ // nanoseconds
+ // processing time of all previous process
+ // transfer between processes
+ public static final String CHAIN_PROCESSING = "x-scb-processing-time";
+
+ private Ticker ticker = Ticker.systemTicker();
+
+ public ProcessingTimeStrategy setTicker(Ticker ticker) {
+ this.ticker = ticker;
+ return this;
+ }
+
+ @Override
+ public String name() {
+ return NAME;
+ }
+
+ @Override
+ public void start(Invocation invocation) {
+ initProcessChainStart(invocation);
+ initChainProcessing(invocation);
+ }
+
+ private void initProcessChainStart(Invocation invocation) {
+ if (invocation.getLocalContext(CHAIN_START_TIME) != null) {
+ return;
+ }
+
+ invocation.addLocalContext(CHAIN_START_TIME, invocation.getInvocationStageTrace().getStart());
+ }
+
+ private void initChainProcessing(Invocation invocation) {
+ if (invocation.getLocalContext(CHAIN_PROCESSING) != null) {
+ return;
+ }
+
+ String contextChainProcessing = invocation.getContext(CHAIN_PROCESSING);
+ long chainProcessingTime = NumberUtils.toLong(contextChainProcessing, 0L);
+ invocation.addLocalContext(CHAIN_PROCESSING, chainProcessingTime);
+ }
+
+ @Override
+ public void beforeSendRequest(Invocation invocation) {
+ InvocationTimeoutStrategy.super.beforeSendRequest(invocation);
+
+ long processingTime = calculateElapsedNanoTime(invocation);
+ invocation.addContext(CHAIN_PROCESSING, Long.toString(processingTime));
+ }
+
+ @Override
+ public long calculateElapsedNanoTime(Invocation invocation) {
+ long chainStartTime = invocation.getLocalContext(CHAIN_START_TIME);
+ long previousProcessingTime = invocation.getLocalContext(CHAIN_PROCESSING);
+ return ticker.read() - chainStartTime + previousProcessingTime;
+ }
+}
diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategyTest.java b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategyTest.java
new file mode 100644
index 0000000..5aa9914
--- /dev/null
+++ b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategyTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.core.invocation.timeout;
+
+import static org.apache.servicecomb.core.invocation.timeout.PassingTimeStrategy.CHAIN_START_TIME;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.test.scaffolding.time.MockClock;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+class PassingTimeStrategyTest {
+ PassingTimeStrategy strategy = new PassingTimeStrategy();
+
+ @Test
+ void should_init_when_start_as_first_chain_node() {
+ Invocation invocation = new Invocation();
+ invocation.getInvocationStageTrace().setStartTimeMillis(10);
+
+ strategy.start(invocation);
+
+ assertThat(invocation.getContext(CHAIN_START_TIME)).isEqualTo("10");
+ assertThat(invocation.<Long>getLocalContext(CHAIN_START_TIME)).isEqualTo(10L);
+ }
+
+ @Test
+ void should_init_when_start_as_first_node_of_a_process_but_not_first_of_a_chain() {
+ Invocation invocation = new Invocation();
+ invocation.setContext(ImmutableMap.of(CHAIN_START_TIME, "10"));
+
+ strategy.start(invocation);
+
+ assertThat(invocation.getContext(CHAIN_START_TIME)).isEqualTo("10");
+ assertThat(invocation.<Long>getLocalContext(CHAIN_START_TIME)).isEqualTo(10L);
+ }
+
+ @Test
+ void should_do_nothing_when_start_not_as_first_node_of_a_process() {
+ Invocation invocation = new Invocation();
+ invocation.setContext(ImmutableMap.of());
+ invocation.setLocalContext(ImmutableMap.of(CHAIN_START_TIME, 10L));
+
+ Throwable throwable = catchThrowable(() -> strategy.start(invocation));
+
+ assertThat(throwable).isNull();
+ }
+
+ @Test
+ void should_calc_elapsed_time_as_passing_time() {
+ Invocation invocation = new Invocation();
+ invocation.addLocalContext(CHAIN_START_TIME, 10L);
+ strategy.setClock(new MockClock(100L));
+
+ long elapsedNanoTime = strategy.calculateElapsedNanoTime(invocation);
+
+ assertThat(elapsedNanoTime).isEqualTo(TimeUnit.MILLISECONDS.toNanos(90));
+ }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategyTest.java b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategyTest.java
new file mode 100644
index 0000000..e348f10
--- /dev/null
+++ b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategyTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.core.invocation.timeout;
+
+import static org.apache.servicecomb.core.invocation.timeout.ProcessingTimeStrategy.CHAIN_PROCESSING;
+import static org.apache.servicecomb.core.invocation.timeout.ProcessingTimeStrategy.CHAIN_START_TIME;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.test.scaffolding.time.MockTicker;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+class ProcessingTimeStrategyTest {
+ ProcessingTimeStrategy strategy = new ProcessingTimeStrategy();
+
+ @Test
+ void should_init_when_start_as_first_chain_node() {
+ Invocation invocation = new Invocation();
+ invocation.getInvocationStageTrace().start(10);
+
+ strategy.start(invocation);
+
+ assertThat(invocation.<Long>getLocalContext(CHAIN_START_TIME)).isEqualTo(10L);
+ assertThat(invocation.<Long>getLocalContext(CHAIN_PROCESSING)).isEqualTo(0L);
+ }
+
+ @Test
+ void should_do_nothing_when_not_first_node_of_a_process() {
+ Invocation invocation = new Invocation();
+ invocation.setLocalContext(ImmutableMap.of(
+ CHAIN_START_TIME, 10L,
+ CHAIN_PROCESSING, 0L
+ ));
+
+ Throwable throwable = catchThrowable(() -> strategy.start(invocation));
+
+ assertThat(throwable).isNull();
+ }
+
+ @Test
+ void should_calc_elapsed_time_as_processing_time() {
+ strategy.setTicker(new MockTicker(50L));
+
+ Invocation invocation = new Invocation();
+ invocation.addLocalContext(CHAIN_START_TIME, 10L);
+ invocation.addLocalContext(CHAIN_PROCESSING, 20L);
+
+ long elapsedNanoTime = strategy.calculateElapsedNanoTime(invocation);
+
+ assertThat(elapsedNanoTime).isEqualTo(60L);
+ }
+
+ @Test
+ void should_update_processing_time_before_send() {
+ strategy = new ProcessingTimeStrategy() {
+ @Override
+ public void checkTimeout(Invocation invocation) {
+
+ }
+ };
+ strategy.setTicker(new MockTicker(50L));
+
+ Invocation invocation = new Invocation();
+ invocation.addLocalContext(CHAIN_START_TIME, 10L);
+ invocation.addLocalContext(CHAIN_PROCESSING, 20L);
+
+ strategy.beforeSendRequest(invocation);
+
+ assertThat(invocation.getContext(CHAIN_PROCESSING)).isEqualTo("60");
+ }
+}
\ No newline at end of file
diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml b/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml
index fd46e82..54b9929 100644
--- a/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml
+++ b/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml
@@ -44,18 +44,20 @@ servicecomb:
timeout: 1000
invocation:
- enableTimeoutCheck: false
+ timeout:
+ check:
+ enabled: false
-# test configurations. you can choose any implementation. default using local.
+ # test configurations. you can choose any implementation. default using local.
# using nacos configuration
-# nacos:
-# serverAddr: http://127.0.0.1:8848
-# group: jaxrstest
-# dataId: jaxrsclient
-# namespace: public
-# contentType: properties # can be properties, yaml, raw. If using raw, property [group].[dataId]=value.
-# addPrefix: false # if true [group].[dataId] will added as properties/yaml items prefix. Will not influence raw.
+ # nacos:
+ # serverAddr: http://127.0.0.1:8848
+ # group: jaxrstest
+ # dataId: jaxrsclient
+ # namespace: public
+ # contentType: properties # can be properties, yaml, raw. If using raw, property [group].[dataId]=value.
+ # addPrefix: false # if true [group].[dataId] will added as properties/yaml items prefix. Will not influence raw.
# for integration test not install any config server
jaxrstest:
diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml b/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml
index 2eda948..a6cb992 100644
--- a/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml
+++ b/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml
@@ -39,4 +39,6 @@ servicecomb:
executors.Provider.ReactiveSchema: servicecomb.executor.reactive
invocation:
- enableTimeoutCheck: false
\ No newline at end of file
+ timeout:
+ check:
+ enabled: false
\ No newline at end of file
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSpringMVCCommonSchemaInterface.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSpringMVCCommonSchemaInterface.java
index e45da0d..a9f53ee 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSpringMVCCommonSchemaInterface.java
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSpringMVCCommonSchemaInterface.java
@@ -19,7 +19,7 @@ package org.apache.servicecomb.demo.springmvc.client;
import java.util.concurrent.TimeUnit;
-import org.apache.servicecomb.core.Const;
+import org.apache.servicecomb.core.invocation.timeout.ProcessingTimeStrategy;
import org.apache.servicecomb.demo.CategorizedTestCase;
import org.apache.servicecomb.demo.CommonSchemaInterface;
import org.apache.servicecomb.demo.TestMgr;
@@ -34,6 +34,7 @@ public class TestSpringMVCCommonSchemaInterface implements CategorizedTestCase {
@RpcReference(schemaId = "SpringMVCCommonSchemaInterface", microserviceName = "springmvc")
private CommonSchemaInterface client;
+ @Override
public void testAllTransport() throws Exception {
testInvocationTimeoutInServer();
testInvocationTimeoutInServerUserCheck();
@@ -54,8 +55,8 @@ public class TestSpringMVCCommonSchemaInterface implements CategorizedTestCase {
private void testInvocationAlreadyTimeoutInClient() {
try {
InvocationContext context = new InvocationContext();
- context.addLocalContext(Const.CONTEXT_TIME_CURRENT, System.nanoTime());
- context.addLocalContext(Const.CONTEXT_TIME_ELAPSED, TimeUnit.SECONDS.toNanos(1));
+ context.addLocalContext(ProcessingTimeStrategy.CHAIN_START_TIME, System.nanoTime());
+ context.addLocalContext(ProcessingTimeStrategy.CHAIN_PROCESSING, TimeUnit.SECONDS.toNanos(1));
client.testInvocationTimeout(context, 1, "hello");
TestMgr.fail("should timeout");
} catch (InvocationException e) {
diff --git a/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml b/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml
index efd5bdf..a1d2dec 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml
+++ b/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml
@@ -51,6 +51,11 @@ servicecomb:
chain:
Consumer:
default: loadbalance,fault-injection-consumer,bizkeeper-consumer
+ invocation:
+ timeout:
+ check:
+ enabled: true
+ strategy: processing-time
tracing:
enabled: true
samplingRate: 0.5
diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml b/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml
index ef9141d..8696bff 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml
+++ b/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml
@@ -61,6 +61,10 @@ servicecomb:
highway:
address: 0.0.0.0:7070?sslEnabled=true
invocation:
+ timeout:
+ check:
+ enabled: true
+ strategy: processing-time
SpringMVCCommonSchemaInterface:
testInvocationTimeout:
timeout: 1000
diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/BootStrapProperties.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/BootStrapProperties.java
index f1b5158..079bf86 100644
--- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/BootStrapProperties.java
+++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/BootStrapProperties.java
@@ -20,8 +20,12 @@ package org.apache.servicecomb.config;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.PropertyConverter;
+import org.apache.commons.configuration.SubsetConfiguration;
import org.springframework.util.StringUtils;
/**
@@ -262,25 +266,33 @@ public class BootStrapProperties {
}
private static Map<String, String> readProperties(Configuration configuration, String newKey, String oldKey) {
- Configuration subset = configuration.subset(newKey);
+ AbstractConfiguration subset = (AbstractConfiguration) configuration.subset(newKey);
if (subset.isEmpty()) {
- subset = configuration.subset(oldKey);
+ subset = (AbstractConfiguration) configuration.subset(oldKey);
}
return toStringMap(subset);
}
- private static Map<String, String> toStringMap(Configuration configuration) {
+ private static Map<String, String> toStringMap(AbstractConfiguration configuration) {
+ AbstractConfiguration root = findRoot(configuration);
Map<String, String> map = new LinkedHashMap<>();
configuration.getKeys().forEachRemaining(key -> {
- try {
- map.put(key, configuration.getString(key));
- } catch (Exception e) {
- map.put(key, String.valueOf(configuration.getProperty(key)));
- }
+ Object value = configuration.getProperty(key);
+ // support placeholder
+ value = PropertyConverter.interpolate(value, root);
+ map.put(key, Objects.toString(value, null));
});
return map;
}
+ private static AbstractConfiguration findRoot(AbstractConfiguration configuration) {
+ if (configuration instanceof SubsetConfiguration) {
+ return findRoot((AbstractConfiguration) ((SubsetConfiguration) configuration).getParent());
+ }
+
+ return configuration;
+ }
+
private static void checkMicroserviceName(String name) {
// the configuration we used
// when resolve placeholder failed
diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/AbstractPropertiesLoader.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/AbstractPropertiesLoader.java
index 8df5f94..1944063 100644
--- a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/AbstractPropertiesLoader.java
+++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/AbstractPropertiesLoader.java
@@ -22,7 +22,6 @@ import java.util.Map;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.StringUtils;
-import org.apache.servicecomb.config.BootStrapProperties;
import org.apache.servicecomb.registry.api.PropertyExtended;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/testing/MockClock.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockClock.java
similarity index 74%
rename from foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/testing/MockClock.java
rename to foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockClock.java
index 252e64b..ba0f3c6 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/testing/MockClock.java
+++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockClock.java
@@ -15,20 +15,28 @@
* limitations under the License.
*/
-package org.apache.servicecomb.foundation.common.testing;
+package org.apache.servicecomb.foundation.test.scaffolding.time;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
-import org.apache.servicecomb.foundation.common.Holder;
-
public class MockClock extends Clock {
+ private MockValues<Long> values;
+
+ public MockClock() {
+ this(0L);
+ }
- Holder<Long> mockMillsHolder;
+ public MockClock(Long... values) {
+ this.setValues(values);
+ }
- public MockClock(Holder<Long> h) {
- this.mockMillsHolder = h;
+ public MockClock setValues(Long... values) {
+ this.values = new MockValues<Long>()
+ .setDefaultValue(0L)
+ .setValues(values);
+ return this;
}
@Override
@@ -48,6 +56,6 @@ public class MockClock extends Clock {
@Override
public long millis() {
- return mockMillsHolder.value;
+ return values.read();
}
}
diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/MockTicker.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockTicker.java
similarity index 64%
copy from foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/MockTicker.java
copy to foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockTicker.java
index 52ceb92..9bd666d 100644
--- a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/MockTicker.java
+++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockTicker.java
@@ -15,42 +15,30 @@
* limitations under the License.
*/
-package org.apache.servicecomb.foundation.test.scaffolding;
+package org.apache.servicecomb.foundation.test.scaffolding.time;
import com.google.common.base.Ticker;
public class MockTicker extends Ticker {
- private long[] values;
-
- private int index;
+ private MockValues<Long> values;
public MockTicker() {
- this(0);
+ this(0L);
}
- public MockTicker(long... values) {
- this.values = values;
- this.index = 0;
+ public MockTicker(Long... values) {
+ this.setValues(values);
}
- public MockTicker setValues(long... values) {
- this.values = values;
- this.index = 0;
+ public MockTicker setValues(Long... values) {
+ this.values = new MockValues<Long>()
+ .setDefaultValue(0L)
+ .setValues(values);
return this;
}
@Override
public long read() {
- if (values.length == 0) {
- return 0;
- }
-
- if (index >= values.length) {
- return values[values.length - 1];
- }
-
- long value = values[index];
- index++;
- return value;
+ return values.read();
}
}
diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/MockTicker.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockValues.java
similarity index 66%
rename from foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/MockTicker.java
rename to foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockValues.java
index 52ceb92..457a8f0 100644
--- a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/MockTicker.java
+++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockValues.java
@@ -15,41 +15,36 @@
* limitations under the License.
*/
-package org.apache.servicecomb.foundation.test.scaffolding;
+package org.apache.servicecomb.foundation.test.scaffolding.time;
-import com.google.common.base.Ticker;
+public class MockValues<T> {
+ private T defaultValue;
-public class MockTicker extends Ticker {
- private long[] values;
+ private T[] values;
private int index;
- public MockTicker() {
- this(0);
- }
-
- public MockTicker(long... values) {
- this.values = values;
- this.index = 0;
+ public MockValues<T> setDefaultValue(T defaultValue) {
+ this.defaultValue = defaultValue;
+ return this;
}
- public MockTicker setValues(long... values) {
+ public MockValues<T> setValues(T[] values) {
this.values = values;
this.index = 0;
return this;
}
- @Override
- public long read() {
- if (values.length == 0) {
- return 0;
+ public T read() {
+ if (values == null || values.length == 0) {
+ return defaultValue;
}
if (index >= values.length) {
return values[values.length - 1];
}
- long value = values[index];
+ T value = values[index];
index++;
return value;
}
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java
index a7aad86..dc6d5d9 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java
@@ -22,8 +22,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.foundation.common.Holder;
-import org.apache.servicecomb.foundation.common.testing.MockClock;
+import org.apache.servicecomb.foundation.test.scaffolding.time.MockClock;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -81,14 +80,14 @@ public class TestServiceCombServerStats {
@Test
public void testTimeWindow() {
- ServiceCombServerStats stats = new ServiceCombServerStats(null, new MockClock(new Holder<>(1000L)));
+ ServiceCombServerStats stats = new ServiceCombServerStats(null, new MockClock(1000L));
Assert.assertEquals(1000, stats.getLastVisitTime());
stats.markSuccess();
stats.markFailure();
Assert.assertEquals(2, stats.getTotalRequests());
Assert.assertEquals(50, stats.getFailedRate());
Assert.assertEquals(50, stats.getSuccessRate());
- stats.clock = new MockClock(new Holder<>(60000L + 2000L));
+ stats.clock = new MockClock(60000L + 2000L);
stats.markSuccess();
Assert.assertEquals(1, stats.getTotalRequests());
Assert.assertEquals(0, stats.getFailedRate());
@@ -118,9 +117,9 @@ public class TestServiceCombServerStats {
Invocation invocation = new Invocation();
Assert.assertTrue(ServiceCombServerStats.applyForTryingChance(invocation));
Assert.assertSame(invocation, ServiceCombServerStats.globalAllowIsolatedServerTryingFlag.get().getInvocation());
- ServiceCombServerStats.globalAllowIsolatedServerTryingFlag.get().clock = new MockClock(new Holder<>(
+ ServiceCombServerStats.globalAllowIsolatedServerTryingFlag.get().clock = new MockClock(
ServiceCombServerStats.globalAllowIsolatedServerTryingFlag.get().startTryingTimestamp + 60000
- ));
+ );
Invocation otherInvocation = new Invocation();
Assert.assertTrue(ServiceCombServerStats.applyForTryingChance(otherInvocation));
diff --git a/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/StoreServiceTest.java b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/StoreServiceTest.java
index 92593c8..6da1304 100644
--- a/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/StoreServiceTest.java
+++ b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/StoreServiceTest.java
@@ -23,7 +23,7 @@ import static org.mockito.Matchers.any;
import java.util.concurrent.CompletableFuture;
-import org.apache.servicecomb.foundation.test.scaffolding.MockTicker;
+import org.apache.servicecomb.foundation.test.scaffolding.time.MockTicker;
import org.apache.servicecomb.registry.api.registry.Microservice;
import org.apache.servicecomb.registry.api.registry.MicroserviceInstanceStatus;
import org.apache.servicecomb.registry.lightweight.store.InstanceStore;
@@ -129,7 +129,7 @@ class StoreServiceTest extends TestBase {
RegisterRequest request = self.buildRegisterRequest()
.setStatus(MicroserviceInstanceStatus.TESTING);
- ticker.setValues(1);
+ ticker.setValues(1L);
InstanceStore instanceStore = service.register(request);
assertThat(self.getInstance().getStatus()).isEqualTo(MicroserviceInstanceStatus.TESTING);
@@ -142,7 +142,7 @@ class StoreServiceTest extends TestBase {
InstanceStore instanceStore = store.findInstanceStore(self.getInstanceId());
assertThat(instanceStore.getLastHeartBeat()).isEqualTo(0);
- ticker.setValues(1);
+ ticker.setValues(1L);
should_register_microservice_and_instance_when_both_not_exist();
assertThat(instanceStore.getLastHeartBeat()).isEqualTo(1);
}
diff --git a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerMock.java b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerMock.java
index 474e56e..89e9ff8 100644
--- a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerMock.java
+++ b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerMock.java
@@ -20,17 +20,17 @@ import java.util.ArrayList;
import org.apache.servicecomb.config.ConfigUtil;
import org.apache.servicecomb.foundation.common.Holder;
-import org.apache.servicecomb.foundation.common.testing.MockClock;
import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
+import org.apache.servicecomb.foundation.test.scaffolding.time.MockClock;
import org.apache.servicecomb.registry.DiscoveryManager;
-import org.apache.servicecomb.serviceregistry.RegistryUtils;
-import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.registry.api.registry.FindInstancesResponse;
import org.apache.servicecomb.registry.api.registry.Microservice;
import org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
-import org.apache.servicecomb.registry.api.registry.FindInstancesResponse;
import org.apache.servicecomb.registry.api.registry.MicroserviceInstances;
import org.apache.servicecomb.registry.consumer.MicroserviceVersions;
import org.apache.servicecomb.registry.definition.DefinitionConst;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
import org.apache.servicecomb.serviceregistry.diagnosis.Status;
import org.apache.servicecomb.serviceregistry.registry.LocalServiceRegistryFactory;
import org.junit.After;
@@ -65,7 +65,7 @@ public class TestInstanceCacheCheckerMock {
RegistryUtils.setServiceRegistry(serviceRegistry);
checker = new InstanceCacheChecker(DiscoveryManager.INSTANCE.getAppManager());
- checker.clock = new MockClock(new Holder<>(1L));
+ checker.clock = new MockClock(1L);
expectedSummary.setStatus(Status.NORMAL);
expectedSummary.setTimestamp(1);
}
diff --git a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerWithoutMock.java b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerWithoutMock.java
index 66a6bdc..4a3b995 100644
--- a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerWithoutMock.java
+++ b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckerWithoutMock.java
@@ -19,9 +19,8 @@ package org.apache.servicecomb.serviceregistry.diagnosis.instance;
import java.util.Arrays;
import org.apache.servicecomb.config.ConfigUtil;
-import org.apache.servicecomb.foundation.common.Holder;
-import org.apache.servicecomb.foundation.common.testing.MockClock;
import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
+import org.apache.servicecomb.foundation.test.scaffolding.time.MockClock;
import org.apache.servicecomb.registry.DiscoveryManager;
import org.apache.servicecomb.registry.RegistrationManager;
import org.apache.servicecomb.registry.consumer.MicroserviceVersionRule;
@@ -62,7 +61,7 @@ public class TestInstanceCacheCheckerWithoutMock {
RegistryUtils.setServiceRegistry(serviceRegistry);
checker = new InstanceCacheChecker(DiscoveryManager.INSTANCE.getAppManager());
- checker.clock = new MockClock(new Holder<>(1L));
+ checker.clock = new MockClock(1L);
expectedSummary.setStatus(Status.NORMAL);
expectedSummary.setTimestamp(1);
}