feat:support async metadata transfer. (#1744)

Signed-off-by: Haotian Zhang <928016560@qq.com>
pull/1757/head
Haotian Zhang 1 month ago committed by GitHub
parent 040a21d6f5
commit 546a6072c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4,3 +4,4 @@
- [feat: upgrade springdoc to 1.8.0.](https://github.com/Tencent/spring-cloud-tencent/pull/1737) - [feat: upgrade springdoc to 1.8.0.](https://github.com/Tencent/spring-cloud-tencent/pull/1737)
- [refactor:optimize auto configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1740) - [refactor:optimize auto configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1740)
- [refactor:optimize config locate.](https://github.com/Tencent/spring-cloud-tencent/pull/1742) - [refactor:optimize config locate.](https://github.com/Tencent/spring-cloud-tencent/pull/1742)
- [feat:support async metadata transfer.](https://github.com/Tencent/spring-cloud-tencent/pull/1744)

@ -17,6 +17,7 @@
package com.tencent.cloud.metadata.config; package com.tencent.cloud.metadata.config;
import com.tencent.cloud.common.async.PolarisAsyncProperties;
import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter; import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter;
import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter; import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter;
@ -64,8 +65,8 @@ public class MetadataTransferAutoConfiguration {
} }
@Bean @Bean
public DecodeTransferMetadataServletFilter metadataServletFilter() { public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisAsyncProperties polarisAsyncProperties) {
return new DecodeTransferMetadataServletFilter(); return new DecodeTransferMetadataServletFilter(polarisAsyncProperties);
} }
} }
@ -77,8 +78,8 @@ public class MetadataTransferAutoConfiguration {
protected static class MetadataReactiveFilterConfig { protected static class MetadataReactiveFilterConfig {
@Bean @Bean
public DecodeTransferMetadataReactiveFilter metadataReactiveFilter() { public DecodeTransferMetadataReactiveFilter metadataReactiveFilter(PolarisAsyncProperties polarisAsyncProperties) {
return new DecodeTransferMetadataReactiveFilter(); return new DecodeTransferMetadataReactiveFilter(polarisAsyncProperties);
} }
} }

@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import com.tencent.cloud.common.async.PolarisAsyncProperties;
import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
@ -56,6 +57,12 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class); private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class);
private final PolarisAsyncProperties polarisAsyncProperties;
public DecodeTransferMetadataReactiveFilter(PolarisAsyncProperties polarisAsyncProperties) {
this.polarisAsyncProperties = polarisAsyncProperties;
}
@Override @Override
public int getOrder() { public int getOrder() {
return OrderConstant.Server.Reactive.DECODE_TRANSFER_METADATA_FILTER_ORDER; return OrderConstant.Server.Reactive.DECODE_TRANSFER_METADATA_FILTER_ORDER;
@ -106,7 +113,8 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
} }
}).build(); }).build();
// message metadata // message metadata
ReactiveMetadataProvider callerMessageMetadataProvider = new ReactiveMetadataProvider(serverHttpRequest, callerIp.get()); ReactiveMetadataProvider callerMessageMetadataProvider = new ReactiveMetadataProvider(serverHttpRequest,
callerIp.get(), polarisAsyncProperties.getEnabled());
MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider); MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider);
@ -115,10 +123,12 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
MetadataConstant.HeaderName.METADATA_CONTEXT, MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get()); MetadataContextHolder.get());
String targetNamespace = serverWebExchange.getRequest().getHeaders().getFirst(MetadataConstant.HeaderName.NAMESPACE); String targetNamespace = serverWebExchange.getRequest().getHeaders()
.getFirst(MetadataConstant.HeaderName.NAMESPACE);
// Compatible with TSF // Compatible with TSF
if (StringUtils.isBlank(targetNamespace)) { if (StringUtils.isBlank(targetNamespace)) {
targetNamespace = serverWebExchange.getRequest().getHeaders().getFirst(MetadataConstant.HeaderName.TSF_NAMESPACE_ID); targetNamespace = serverWebExchange.getRequest().getHeaders()
.getFirst(MetadataConstant.HeaderName.TSF_NAMESPACE_ID);
} }
if (StringUtils.isNotBlank(targetNamespace)) { if (StringUtils.isNotBlank(targetNamespace)) {

@ -27,6 +27,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.tencent.cloud.common.async.PolarisAsyncProperties;
import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
@ -58,6 +59,12 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class); private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class);
private final PolarisAsyncProperties polarisAsyncProperties;
public DecodeTransferMetadataServletFilter(PolarisAsyncProperties polarisAsyncProperties) {
this.polarisAsyncProperties = polarisAsyncProperties;
}
@Override @Override
protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest,
@NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain)
@ -100,7 +107,8 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
// add headers // add headers
httpServletRequest = new HttpServletRequestHeaderWrapper(httpServletRequest, addHeaders); httpServletRequest = new HttpServletRequestHeaderWrapper(httpServletRequest, addHeaders);
// message metadata // message metadata
ServletMetadataProvider callerMessageMetadataProvider = new ServletMetadataProvider(httpServletRequest, callerIp.get()); ServletMetadataProvider callerMessageMetadataProvider = new ServletMetadataProvider(httpServletRequest,
callerIp.get(), polarisAsyncProperties.getEnabled());
MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider); MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider);

@ -0,0 +1,510 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.metadata.pojo;
import java.io.BufferedReader;
import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpUpgradeHandler;
import javax.servlet.http.Part;
import org.springframework.http.HttpHeaders;
/**
* Snapshot of HttpServletRequest.
*
* @author Haotian Zhang
*/
public final class SnapshotHttpServletRequest implements HttpServletRequest {
/**
* HTTP method.
*/
private final String method;
/**
* Request URI.
*/
private final String requestURI;
/**
* Query string.
*/
private final String queryString;
/**
* HTTP headers.
*/
private final HttpHeaders headers;
/**
* HTTP cookies.
*/
private final Cookie[] cookies;
private SnapshotHttpServletRequest(Builder builder) {
this.method = builder.method;
this.requestURI = builder.requestURI;
this.queryString = builder.queryString;
this.headers = HttpHeaders.readOnlyHttpHeaders(builder.headers);
this.cookies = builder.cookies != null ? builder.cookies.clone() : null;
}
/**
* create SnapshotHttpServletRequest from HttpServletRequest.
*
* @param request original request
* @return snapshot
*/
public static SnapshotHttpServletRequest from(HttpServletRequest request) {
Builder builder = new Builder()
.method(request.getMethod())
.requestURI(request.getRequestURI())
.queryString(request.getQueryString())
.cookies(request.getCookies());
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
Enumeration<String> headerValues = request.getHeaders(headerName);
if (headerValues != null) {
while (headerValues.hasMoreElements()) {
builder.header(headerName, headerValues.nextElement());
}
}
}
}
return builder.build();
}
public static Builder builder() {
return new Builder();
}
@Override
public String getMethod() {
return method;
}
@Override
public String getRequestURI() {
return requestURI;
}
@Override
public String getQueryString() {
return queryString;
}
@Override
public String getHeader(String name) {
return headers.getFirst(name);
}
@Override
public Enumeration<String> getHeaders(String name) {
List<String> values = headers.get(name);
if (values != null && !values.isEmpty()) {
return Collections.enumeration(values);
}
return Collections.enumeration(Collections.emptyList());
}
@Override
public Enumeration<String> getHeaderNames() {
return Collections.enumeration(headers.keySet());
}
@Override
public Cookie[] getCookies() {
return cookies != null ? cookies.clone() : null;
}
// ========== Unsupported operations ==========
@Override
public String getAuthType() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getPathInfo() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getPathTranslated() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getContextPath() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getRemoteUser() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isUserInRole(String role) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Principal getUserPrincipal() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getRequestedSessionId() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public StringBuffer getRequestURL() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getServletPath() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public HttpSession getSession(boolean create) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public HttpSession getSession() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String changeSessionId() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isRequestedSessionIdValid() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isRequestedSessionIdFromCookie() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isRequestedSessionIdFromURL() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isRequestedSessionIdFromUrl() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public void login(String username, String password) throws ServletException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public void logout() throws ServletException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Collection<Part> getParts() throws IOException, ServletException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Part getPart(String name) throws IOException, ServletException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public long getContentLengthLong() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public ServletInputStream getInputStream() throws IOException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getParameter(String name) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Enumeration<String> getParameterNames() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String[] getParameterValues(String name) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Map<String, String[]> getParameterMap() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getProtocol() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getScheme() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getServerName() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public int getServerPort() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public BufferedReader getReader() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getRemoteAddr() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getRemoteHost() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public void setAttribute(String name, Object o) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public void removeAttribute(String name) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Locale getLocale() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Enumeration<Locale> getLocales() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isSecure() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getRealPath(String path) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public int getRemotePort() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getLocalName() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getLocalAddr() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public int getLocalPort() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public ServletContext getServletContext() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isAsyncStarted() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public boolean isAsyncSupported() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public AsyncContext getAsyncContext() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public DispatcherType getDispatcherType() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Object getAttribute(String name) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public Enumeration<String> getAttributeNames() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getCharacterEncoding() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public void setCharacterEncoding(String env) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public int getContentLength() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public String getContentType() {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public int getIntHeader(String name) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
@Override
public long getDateHeader(String name) {
throw new UnsupportedOperationException("Snapshot request does not support this operation");
}
public static class Builder {
private String method;
private String requestURI;
private String queryString;
private HttpHeaders headers = new HttpHeaders();
private Cookie[] cookies;
public Builder method(String method) {
this.method = method;
return this;
}
public Builder requestURI(String requestURI) {
this.requestURI = requestURI;
return this;
}
public Builder queryString(String queryString) {
this.queryString = queryString;
return this;
}
public Builder header(String name, String value) {
if (name != null && value != null) {
this.headers.add(name, value);
}
return this;
}
public Builder cookies(Cookie[] cookies) {
if (cookies != null) {
this.cookies = cookies.clone();
}
return this;
}
public SnapshotHttpServletRequest build() {
return new SnapshotHttpServletRequest(this);
}
}
}

@ -0,0 +1,253 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.metadata.pojo;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import reactor.core.publisher.Flux;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* Snapshot of ServerHttpRequest.
*
* @author Haotian Zhang
*/
public final class SnapshotServerHttpRequest implements ServerHttpRequest {
/**
* HTTP method.
*/
private final HttpMethod method;
/**
* HTTP URI.
*/
private final URI uri;
/**
* HTTP attributes.
*/
private final Map<String, Object> attributes;
/**
* HTTP path.
*/
private final String path;
/**
* HTTP headers.
*/
private final HttpHeaders headers;
/**
* HTTP query params.
*/
private final MultiValueMap<String, String> queryParams;
/**
* HTTP cookies.
*/
private final MultiValueMap<String, HttpCookie> cookies;
/**
* HTTP remote address.
*/
private final InetSocketAddress remoteAddress;
/**
* HTTP local address.
*/
private final InetSocketAddress localAddress;
/**
* HTTP request id.
*/
private final String id;
private SnapshotServerHttpRequest(Builder builder) {
this.method = builder.method;
this.uri = builder.uri;
this.attributes = builder.attributes;
this.path = builder.path;
this.headers = HttpHeaders.readOnlyHttpHeaders(builder.headers);
this.queryParams = new LinkedMultiValueMap<>(builder.queryParams);
this.cookies = new LinkedMultiValueMap<>(builder.cookies);
this.remoteAddress = builder.remoteAddress;
this.localAddress = builder.localAddress;
this.id = builder.id;
}
/**
* create SnapshotServerHttpRequest from ServerHttpRequest.
*
* @param request original request
* @return snapshot
*/
public static SnapshotServerHttpRequest from(ServerHttpRequest request) {
return new Builder()
.method(request.getMethod())
.uri(request.getURI())
.path(request.getPath().value())
.headers(request.getHeaders())
.queryParams(request.getQueryParams())
.cookies(request.getCookies())
.remoteAddress(request.getRemoteAddress())
.localAddress(request.getLocalAddress())
.id(request.getId())
.build();
}
public static Builder builder() {
return new Builder();
}
@Override
public String getMethodValue() {
return method.name();
}
@Override
public URI getURI() {
return uri;
}
@Override
public RequestPath getPath() {
return RequestPath.parse(path, null);
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
@Override
public MultiValueMap<String, String> getQueryParams() {
return queryParams;
}
@Override
public MultiValueMap<String, HttpCookie> getCookies() {
return cookies;
}
@Override
public InetSocketAddress getRemoteAddress() {
return remoteAddress;
}
@Override
public InetSocketAddress getLocalAddress() {
return localAddress;
}
@Override
public String getId() {
return id;
}
@Override
public Flux<DataBuffer> getBody() {
throw new UnsupportedOperationException("Snapshot request does not support body access");
}
public static class Builder {
private HttpMethod method;
private URI uri;
private Map<String, Object> attributes = new HashMap<>();
private String path;
private HttpHeaders headers = new HttpHeaders();
private MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
private MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>();
private InetSocketAddress remoteAddress;
private InetSocketAddress localAddress;
private String id;
public Builder method(HttpMethod method) {
this.method = method;
return this;
}
public Builder uri(URI uri) {
this.uri = uri;
return this;
}
public Builder attributes(Map<String, Object> attributes) {
this.attributes = attributes;
return this;
}
public Builder path(String path) {
this.path = path;
return this;
}
public Builder headers(HttpHeaders headers) {
if (headers != null) {
this.headers = new HttpHeaders();
this.headers.putAll(headers);
}
return this;
}
public Builder queryParams(MultiValueMap<String, String> queryParams) {
if (queryParams != null) {
this.queryParams = new LinkedMultiValueMap<>(queryParams);
}
return this;
}
public Builder cookies(MultiValueMap<String, HttpCookie> cookies) {
if (cookies != null) {
this.cookies = new LinkedMultiValueMap<>(cookies);
}
return this;
}
public Builder remoteAddress(InetSocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
return this;
}
public Builder localAddress(InetSocketAddress localAddress) {
this.localAddress = localAddress;
return this;
}
public Builder id(String id) {
this.id = id;
return this;
}
public SnapshotServerHttpRequest build() {
return new SnapshotServerHttpRequest(this);
}
}
}

@ -43,7 +43,7 @@ public class FeignRequestTemplateMetadataProvider implements MetadataProvider {
} }
@Override @Override
public String getRawMetadataStringValue(String key) { public String doGetRawMetadataStringValue(String key) {
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_KEY_METHOD: case MessageMetadataContainer.LABEL_KEY_METHOD:
return requestTemplate.method(); return requestTemplate.method();
@ -59,7 +59,7 @@ public class FeignRequestTemplateMetadataProvider implements MetadataProvider {
} }
@Override @Override
public String getRawMetadataMapValue(String key, String mapKey) { public String doGetRawMetadataMapValue(String key, String mapKey) {
Map<String, Collection<String>> headers = requestTemplate.headers(); Map<String, Collection<String>> headers = requestTemplate.headers();
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:

@ -19,6 +19,8 @@ package com.tencent.cloud.metadata.provider;
import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils;
import com.tencent.cloud.metadata.pojo.SnapshotServerHttpRequest;
import com.tencent.polaris.annonation.JustForTest;
import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.polaris.metadata.core.MetadataProvider; import com.tencent.polaris.metadata.core.MetadataProvider;
@ -31,17 +33,26 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
*/ */
public class ReactiveMetadataProvider implements MetadataProvider { public class ReactiveMetadataProvider implements MetadataProvider {
private ServerHttpRequest serverHttpRequest; private final ServerHttpRequest serverHttpRequest;
private String callerIp; private final String callerIp;
public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest, String callerIp) { public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest, String callerIp) {
this.serverHttpRequest = serverHttpRequest; this(serverHttpRequest, callerIp, false);
}
public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest, String callerIp, boolean isAsync) {
if (isAsync) {
this.serverHttpRequest = SnapshotServerHttpRequest.from(serverHttpRequest);
}
else {
this.serverHttpRequest = serverHttpRequest;
}
this.callerIp = callerIp; this.callerIp = callerIp;
} }
@Override @Override
public String getRawMetadataStringValue(String key) { public String doGetRawMetadataStringValue(String key) {
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_KEY_METHOD: case MessageMetadataContainer.LABEL_KEY_METHOD:
return serverHttpRequest.getMethod().name(); return serverHttpRequest.getMethod().name();
@ -55,16 +66,21 @@ public class ReactiveMetadataProvider implements MetadataProvider {
} }
@Override @Override
public String getRawMetadataMapValue(String key, String mapKey) { public String doGetRawMetadataMapValue(String key, String mapKey) {
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:
return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(serverHttpRequest, mapKey, null)); return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(serverHttpRequest, mapKey, null));
case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE:
return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(serverHttpRequest, mapKey, null)); return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(serverHttpRequest, mapKey, null));
case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: case MessageMetadataContainer.LABEL_MAP_KEY_QUERY:
return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(serverHttpRequest, mapKey, null)); return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(serverHttpRequest, mapKey, null));
default: default:
return null; return null;
} }
} }
@JustForTest
ServerHttpRequest getServerHttpRequest() {
return serverHttpRequest;
}
} }

@ -40,7 +40,7 @@ public class RestTemplateMetadataProvider implements MetadataProvider {
} }
@Override @Override
public String getRawMetadataStringValue(String key) { public String doGetRawMetadataStringValue(String key) {
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_KEY_METHOD: case MessageMetadataContainer.LABEL_KEY_METHOD:
return request.getMethod().toString(); return request.getMethod().toString();
@ -55,7 +55,7 @@ public class RestTemplateMetadataProvider implements MetadataProvider {
} }
@Override @Override
public String getRawMetadataMapValue(String key, String mapKey) { public String doGetRawMetadataMapValue(String key, String mapKey) {
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:
return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(request, mapKey)); return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(request, mapKey));

@ -21,6 +21,8 @@ import javax.servlet.http.HttpServletRequest;
import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
import com.tencent.cloud.common.util.expresstion.ServletExpressionLabelUtils; import com.tencent.cloud.common.util.expresstion.ServletExpressionLabelUtils;
import com.tencent.cloud.metadata.pojo.SnapshotHttpServletRequest;
import com.tencent.polaris.annonation.JustForTest;
import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.polaris.metadata.core.MetadataProvider; import com.tencent.polaris.metadata.core.MetadataProvider;
@ -32,40 +34,54 @@ import com.tencent.polaris.metadata.core.MetadataProvider;
*/ */
public class ServletMetadataProvider implements MetadataProvider { public class ServletMetadataProvider implements MetadataProvider {
private HttpServletRequest httpServletRequest; private final HttpServletRequest httpServletRequest;
private String callerIp; private final String callerIp;
public ServletMetadataProvider(HttpServletRequest httpServletRequest, String callerIp) { public ServletMetadataProvider(HttpServletRequest httpServletRequest, String callerIp) {
this.httpServletRequest = httpServletRequest; this(httpServletRequest, callerIp, false);
}
public ServletMetadataProvider(HttpServletRequest httpServletRequest, String callerIp, boolean isAsync) {
if (isAsync) {
this.httpServletRequest = SnapshotHttpServletRequest.from(httpServletRequest);
}
else {
this.httpServletRequest = httpServletRequest;
}
this.callerIp = callerIp; this.callerIp = callerIp;
} }
@Override @Override
public String getRawMetadataStringValue(String key) { public String doGetRawMetadataStringValue(String key) {
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_KEY_METHOD: case MessageMetadataContainer.LABEL_KEY_METHOD:
return httpServletRequest.getMethod(); return httpServletRequest.getMethod();
case MessageMetadataContainer.LABEL_KEY_PATH: case MessageMetadataContainer.LABEL_KEY_PATH:
return UrlUtils.decode(httpServletRequest.getRequestURI()); return UrlUtils.decode(httpServletRequest.getRequestURI());
case MessageMetadataContainer.LABEL_KEY_CALLER_IP: case MessageMetadataContainer.LABEL_KEY_CALLER_IP:
return callerIp; return callerIp;
default: default:
return null; return null;
} }
} }
@Override @Override
public String getRawMetadataMapValue(String key, String mapKey) { public String doGetRawMetadataMapValue(String key, String mapKey) {
switch (key) { switch (key) {
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:
return UrlUtils.decode(httpServletRequest.getHeader(mapKey)); return UrlUtils.decode(httpServletRequest.getHeader(mapKey));
case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE:
return UrlUtils.decode(ServletExpressionLabelUtils.getCookieValue(httpServletRequest.getCookies(), mapKey, null)); return UrlUtils.decode(ServletExpressionLabelUtils.getCookieValue(httpServletRequest.getCookies(), mapKey, null));
case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: case MessageMetadataContainer.LABEL_MAP_KEY_QUERY:
return UrlUtils.decode(ExpressionLabelUtils.getQueryValue(httpServletRequest.getQueryString(), mapKey, null)); return UrlUtils.decode(ExpressionLabelUtils.getQueryValue(httpServletRequest.getQueryString(), mapKey, null));
default: default:
return null; return null;
} }
} }
@JustForTest
HttpServletRequest getHttpServletRequest() {
return httpServletRequest;
}
} }

@ -17,6 +17,7 @@
package com.tencent.cloud.metadata.config; package com.tencent.cloud.metadata.config;
import com.tencent.cloud.common.async.PolarisAsyncProperties;
import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin;
import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
@ -61,7 +62,11 @@ public class MetadataTransferAutoConfigurationTest {
*/ */
@Test @Test
public void test2() { public void test2() {
this.reactiveWebApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class, PolarisContextProperties.class)) this.reactiveWebApplicationContextRunner.withConfiguration(
AutoConfigurations.of(
MetadataTransferAutoConfiguration.class,
PolarisContextProperties.class,
PolarisAsyncProperties.class))
.run(context -> { .run(context -> {
assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class);
assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class);

@ -17,6 +17,7 @@
package com.tencent.cloud.metadata.core; package com.tencent.cloud.metadata.core;
import com.tencent.cloud.common.async.PolarisAsyncProperties;
import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
@ -50,11 +51,14 @@ public class DecodeTransferMetadataReactiveFilterTest {
@Autowired @Autowired
private MetadataLocalProperties metadataLocalProperties; private MetadataLocalProperties metadataLocalProperties;
@Autowired
private PolarisAsyncProperties polarisAsyncProperties;
private DecodeTransferMetadataReactiveFilter metadataReactiveFilter; private DecodeTransferMetadataReactiveFilter metadataReactiveFilter;
@BeforeEach @BeforeEach
public void setUp() { public void setUp() {
this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(); this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(polarisAsyncProperties);
} }
@Test @Test

@ -18,28 +18,26 @@
package com.tencent.cloud.metadata.provider; package com.tencent.cloud.metadata.provider;
import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.metadata.pojo.SnapshotServerHttpRequest;
import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.HttpCookie; import org.springframework.http.HttpCookie;
import org.springframework.http.HttpMethod;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.MockCookie;
import org.springframework.mock.web.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Test for {@link ReactiveMetadataProvider} and {@link ServletMetadataProvider}. * Test for {@link ReactiveMetadataProvider}.
* *
* @author quan, Shedfree Wu * @author Haotian Zhang, Shedfree Wu
*/ */
public class MetadataProviderTest { public class ReactiveMetadataProviderTest {
private static final String notExistKey = "empty"; private static final String notExistKey = "empty";
@Test @Test
public void testReactiveMetadataProvider() { public void testReactiveMetadataProviderWithoutAsync() {
String headerKey1 = "header1"; String headerKey1 = "header1";
String headerKey2 = "header2"; String headerKey2 = "header2";
String headerValue1 = "value1"; String headerValue1 = "value1";
@ -64,6 +62,7 @@ public class MetadataProviderTest {
.build(); .build();
ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp); ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp);
assertThat(reactiveMetadataProvider.getServerHttpRequest()).isNotInstanceOf(SnapshotServerHttpRequest.class);
assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1);
assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2);
// com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist
@ -89,7 +88,7 @@ public class MetadataProviderTest {
} }
@Test @Test
public void testServletMetadataProvider() { public void testReactiveMetadataProviderWithAsync() {
String headerKey1 = "header1"; String headerKey1 = "header1";
String headerKey2 = "header2"; String headerKey2 = "header2";
String headerValue1 = "value1"; String headerValue1 = "value1";
@ -104,35 +103,38 @@ public class MetadataProviderTest {
String cookieValue2 = "cv2/test"; String cookieValue2 = "cv2/test";
String path = "/echo/test"; String path = "/echo/test";
String callerIp = "localhost"; String callerIp = "localhost";
MockHttpServletRequest request = new MockHttpServletRequest(); MockServerHttpRequest request = MockServerHttpRequest.get(path)
request.addHeader(headerKey1, headerValue1); .header(headerKey1, headerValue1)
request.addHeader(headerKey2, UrlUtils.encode(headerValue2)); .header(headerKey2, UrlUtils.encode(headerValue2))
request.setCookies(new MockCookie(cookieKey1, cookieValue1), new MockCookie(cookieKey2, UrlUtils.encode(cookieValue2))); .queryParam(queryKey1, queryValue1)
request.setMethod(HttpMethod.GET.name()); .queryParam(queryKey2, UrlUtils.encode(queryValue2))
request.setRequestURI(path); .cookie(new HttpCookie(cookieKey1, cookieValue1))
request.setQueryString(queryKey1 + "=" + queryValue1 + "&" + queryKey2 + "=" + UrlUtils.encode(queryValue2)); .cookie(new HttpCookie(cookieKey2, UrlUtils.encode(cookieValue2)))
.build();
ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request, callerIp);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp, true);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); assertThat(reactiveMetadataProvider.getServerHttpRequest()).isInstanceOf(SnapshotServerHttpRequest.class);
assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1);
assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2);
// com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull(); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull(); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull(); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull(); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull();
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET");
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path);
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp); assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp);
assertThat(servletMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); assertThat(reactiveMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull();
request.setRequestURI("/echo/" + UrlUtils.decode("a@b")); request = MockServerHttpRequest.get("/echo/" + UrlUtils.decode("a@b")).build();
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp);
assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b");
} }
} }

@ -0,0 +1,138 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.metadata.provider;
import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.metadata.pojo.SnapshotHttpServletRequest;
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockCookie;
import org.springframework.mock.web.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link ServletMetadataProvider}.
*
* @author Haotian Zhang, Shedfree Wu
*/
public class ServletMetadataProviderTest {
private static final String notExistKey = "empty";
@Test
public void testServletMetadataProviderWithoutAsync() {
String headerKey1 = "header1";
String headerKey2 = "header2";
String headerValue1 = "value1";
String headerValue2 = "value2/test";
String queryKey1 = "qk1";
String queryKey2 = "qk2";
String queryValue1 = "qv1";
String queryValue2 = "qv2/test";
String cookieKey1 = "ck1";
String cookieKey2 = "ck2";
String cookieValue1 = "cv1";
String cookieValue2 = "cv2/test";
String path = "/echo/test";
String callerIp = "localhost";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader(headerKey1, headerValue1);
request.addHeader(headerKey2, UrlUtils.encode(headerValue2));
request.setCookies(new MockCookie(cookieKey1, cookieValue1), new MockCookie(cookieKey2, UrlUtils.encode(cookieValue2)));
request.setMethod(HttpMethod.GET.name());
request.setRequestURI(path);
request.setQueryString(queryKey1 + "=" + queryValue1 + "&" + queryKey2 + "=" + UrlUtils.encode(queryValue2));
ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request, callerIp);
assertThat(servletMetadataProvider.getHttpServletRequest()).isNotInstanceOf(SnapshotHttpServletRequest.class);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2);
// com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull();
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET");
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path);
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp);
assertThat(servletMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull();
request.setRequestURI("/echo/" + UrlUtils.decode("a@b"));
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b");
}
@Test
public void testServletMetadataProviderWithAsync() {
String headerKey1 = "header1";
String headerKey2 = "header2";
String headerValue1 = "value1";
String headerValue2 = "value2/test";
String queryKey1 = "qk1";
String queryKey2 = "qk2";
String queryValue1 = "qv1";
String queryValue2 = "qv2/test";
String cookieKey1 = "ck1";
String cookieKey2 = "ck2";
String cookieValue1 = "cv1";
String cookieValue2 = "cv2/test";
String path = "/echo/test";
String callerIp = "localhost";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader(headerKey1, headerValue1);
request.addHeader(headerKey2, UrlUtils.encode(headerValue2));
request.setCookies(new MockCookie(cookieKey1, cookieValue1), new MockCookie(cookieKey2, UrlUtils.encode(cookieValue2)));
request.setMethod(HttpMethod.GET.name());
request.setRequestURI(path);
request.setQueryString(queryKey1 + "=" + queryValue1 + "&" + queryKey2 + "=" + UrlUtils.encode(queryValue2));
ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request, callerIp, true);
assertThat(servletMetadataProvider.getHttpServletRequest()).isInstanceOf(SnapshotHttpServletRequest.class);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2);
// com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2);
assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull();
assertThat(servletMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull();
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET");
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path);
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp);
assertThat(servletMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull();
request.setRequestURI("/echo/" + UrlUtils.decode("a@b"));
servletMetadataProvider = new ServletMetadataProvider(request, callerIp, true);
assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b");
}
}

@ -0,0 +1,49 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.common.async;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Metadata Properties from local properties file.
*
* @author Haotian Zhang
*/
@ConfigurationProperties(prefix = "spring.cloud.tencent.async")
public class PolarisAsyncProperties {
/**
* Enable async or not.
*/
private Boolean enabled = false;
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
@Override
public String toString() {
return "PolarisAsyncProperties{" +
"enabled=" + enabled +
'}';
}
}

@ -0,0 +1,36 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.common.async;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Autoconfiguration of polaris async.
*
* @author Haotian Zhang
*/
@Configuration(proxyBeanMethods = false)
public class PolarisAsyncPropertiesAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public PolarisAsyncProperties polarisAsyncProperties() {
return new PolarisAsyncProperties();
}
}

@ -96,4 +96,14 @@ public class MetadataLocalProperties {
public void setHeaders(List<String> headers) { public void setHeaders(List<String> headers) {
this.headers = headers; this.headers = headers;
} }
@Override
public String toString() {
return "MetadataLocalProperties{" +
"content=" + content +
", transitive=" + transitive +
", disposable=" + disposable +
", headers=" + headers +
'}';
}
} }

@ -22,6 +22,8 @@ import java.util.function.Supplier;
import com.tencent.polaris.threadlocal.cross.CompletableFutureUtils; import com.tencent.polaris.threadlocal.cross.CompletableFutureUtils;
import org.springframework.util.Assert;
import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_CONSUMER; import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_CONSUMER;
import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_SUPPLIER; import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_SUPPLIER;
@ -36,10 +38,14 @@ public final class PolarisCompletableFutureUtils {
} }
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) { public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
Assert.notNull(supplier, "Supplier must not be null");
return CompletableFutureUtils.supplyAsync(supplier, CROSS_THREAD_METADATA_CONTEXT_SUPPLIER, CROSS_THREAD_METADATA_CONTEXT_CONSUMER); return CompletableFutureUtils.supplyAsync(supplier, CROSS_THREAD_METADATA_CONTEXT_SUPPLIER, CROSS_THREAD_METADATA_CONTEXT_CONSUMER);
} }
public static CompletableFuture<Void> runAsync(Runnable runnable) { public static CompletableFuture<Void> runAsync(Runnable runnable) {
Assert.notNull(runnable, "Runnable must not be null");
return CompletableFutureUtils.runAsync(runnable, CROSS_THREAD_METADATA_CONTEXT_SUPPLIER, CROSS_THREAD_METADATA_CONTEXT_CONSUMER); return CompletableFutureUtils.runAsync(runnable, CROSS_THREAD_METADATA_CONTEXT_SUPPLIER, CROSS_THREAD_METADATA_CONTEXT_CONSUMER);
} }
} }

@ -2,6 +2,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.common.util.inet.PolarisInetUtilsAutoConfiguration,\ com.tencent.cloud.common.util.inet.PolarisInetUtilsAutoConfiguration,\
com.tencent.cloud.common.util.ApplicationContextAwareUtils,\ com.tencent.cloud.common.util.ApplicationContextAwareUtils,\
com.tencent.cloud.common.metadata.config.MetadataAutoConfiguration,\ com.tencent.cloud.common.metadata.config.MetadataAutoConfiguration,\
com.tencent.cloud.common.metadata.endpoint.PolarisMetadataEndpointAutoConfiguration com.tencent.cloud.common.metadata.endpoint.PolarisMetadataEndpointAutoConfiguration,\
com.tencent.cloud.common.async.PolarisAsyncPropertiesAutoConfiguration,\
com.tencent.cloud.common.async.PolarisAsyncConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.common.util.inet.PolarisInetUtilsBootstrapConfiguration com.tencent.cloud.common.util.inet.PolarisInetUtilsBootstrapConfiguration

@ -0,0 +1,83 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.common.async;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
/**
* Test for {@link PolarisAsyncPropertiesAutoConfiguration}.
*
* @author Haotian Zhang
*/
public class PolarisAsyncPropertiesAutoConfigurationTest {
private final ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner().withPropertyValues(
"spring.application.name=test"
);
private final WebApplicationContextRunner webApplicationContextRunner = new WebApplicationContextRunner().withPropertyValues(
"spring.application.name=test"
);
private final ReactiveWebApplicationContextRunner reactiveWebApplicationContextRunner = new ReactiveWebApplicationContextRunner().withPropertyValues(
"spring.application.name=test"
);
/**
* No any web application.
*/
@Test
public void test1() {
this.applicationContextRunner
.withConfiguration(AutoConfigurations.of(PolarisAsyncPropertiesAutoConfiguration.class))
.run(context -> {
Assertions.assertThat(context).hasSingleBean(PolarisAsyncProperties.class);
});
}
/**
* web application.
*/
@Test
public void test2() {
this.webApplicationContextRunner
.withConfiguration(AutoConfigurations.of(PolarisAsyncPropertiesAutoConfiguration.class))
.run(context -> {
Assertions.assertThat(context).hasSingleBean(PolarisAsyncProperties.class);
});
}
/**
* reactive web application.
*/
@Test
public void test3() {
this.reactiveWebApplicationContextRunner
.withConfiguration(AutoConfigurations.of(PolarisAsyncPropertiesAutoConfiguration.class))
.run(context -> {
Assertions.assertThat(context).hasSingleBean(PolarisAsyncProperties.class);
});
}
}

@ -0,0 +1,53 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.common.async;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link PolarisAsyncProperties}.
*
* @author Haotian Zhang
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = PolarisAsyncPropertiesTest.TestApplication.class,
properties = {"spring.config.location = classpath:application-test.yml"})
public class PolarisAsyncPropertiesTest {
@Autowired
private PolarisAsyncProperties polarisAsyncProperties;
@Test
public void test() {
assertThat(polarisAsyncProperties.getEnabled()).isTrue();
}
@SpringBootApplication
protected static class TestApplication {
}
}

@ -17,7 +17,6 @@
package com.tencent.cloud.common.metadata.config; package com.tencent.cloud.common.metadata.config;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -26,6 +25,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Test for {@link MetadataLocalProperties}. * Test for {@link MetadataLocalProperties}.
* *
@ -42,20 +43,20 @@ public class MetadataLocalPropertiesTest {
@Test @Test
public void test1() { public void test1() {
Assertions.assertThat(metadataLocalProperties.getContent().get("a")).isEqualTo("1"); assertThat(metadataLocalProperties.getContent().get("a")).isEqualTo("1");
Assertions.assertThat(metadataLocalProperties.getContent().get("b")).isEqualTo("2"); assertThat(metadataLocalProperties.getContent().get("b")).isEqualTo("2");
Assertions.assertThat(metadataLocalProperties.getContent().get("c")).isNull(); assertThat(metadataLocalProperties.getContent().get("c")).isNull();
} }
@Test @Test
public void test2() { public void test2() {
Assertions.assertThat(metadataLocalProperties.getTransitive().contains("b")).isTrue(); assertThat(metadataLocalProperties.getTransitive().contains("b")).isTrue();
} }
@Test @Test
public void test3() { public void test3() {
Assertions.assertThat(metadataLocalProperties.getHeaders().contains("c")).isTrue(); assertThat(metadataLocalProperties.getHeaders().contains("c")).isTrue();
Assertions.assertThat(metadataLocalProperties.getHeaders().contains("d")).isTrue(); assertThat(metadataLocalProperties.getHeaders().contains("d")).isTrue();
} }
@SpringBootApplication @SpringBootApplication

@ -17,6 +17,8 @@
package com.tencent.cloud.common.util; package com.tencent.cloud.common.util;
import java.util.concurrent.CompletableFuture;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
@ -24,6 +26,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/** /**
* Test for {@link PolarisCompletableFutureUtils}. * Test for {@link PolarisCompletableFutureUtils}.
@ -45,6 +48,22 @@ public class PolarisCompletableFutureUtilsTest {
@Test @Test
public void testSupplyAsync() { public void testSupplyAsync() {
// can not be found and set
CompletableFuture.supplyAsync(() -> {
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isNull();
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isNull();
return "test";
}).thenAccept(result -> {
assertThat(result).isEqualTo("test");
}).join();
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isEqualTo("value1");
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isNull();
// can be found and set
PolarisCompletableFutureUtils.supplyAsync(() -> { PolarisCompletableFutureUtils.supplyAsync(() -> {
assertThat(MetadataContextHolder.get() assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isEqualTo("value1"); .getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isEqualTo("value1");
@ -61,8 +80,28 @@ public class PolarisCompletableFutureUtilsTest {
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isEqualTo("value2"); .getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isEqualTo("value2");
} }
@Test
public void testSupplyAsyncWithNullSupplier() {
assertThatThrownBy(() -> PolarisCompletableFutureUtils.supplyAsync(null))
.isExactlyInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Supplier must not be null");
}
@Test @Test
public void testRunAsync() { public void testRunAsync() {
// can not be found and set
CompletableFuture.runAsync(() -> {
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isNull();
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isNull();
}).join();
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isEqualTo("value1");
assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isNull();
// can be found and set
PolarisCompletableFutureUtils.runAsync(() -> { PolarisCompletableFutureUtils.runAsync(() -> {
assertThat(MetadataContextHolder.get() assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isEqualTo("value1"); .getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key1")).isEqualTo("value1");
@ -75,4 +114,11 @@ public class PolarisCompletableFutureUtilsTest {
assertThat(MetadataContextHolder.get() assertThat(MetadataContextHolder.get()
.getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isEqualTo("value3"); .getContext(MetadataContext.FRAGMENT_TRANSITIVE, "key2")).isEqualTo("value3");
} }
@Test
public void testRunAsyncWithNullRunnable() {
assertThatThrownBy(() -> PolarisCompletableFutureUtils.runAsync(null))
.isExactlyInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Runnable must not be null");
}
} }

@ -17,3 +17,5 @@ spring:
headers: headers:
- c - c
- d - d
async:
enabled: true

@ -74,7 +74,7 @@
<revision>2.1.1.0-2021.0.9-SNAPSHOT</revision> <revision>2.1.1.0-2021.0.9-SNAPSHOT</revision>
<!-- Polaris SDK version --> <!-- Polaris SDK version -->
<polaris.version>2.1.0.0</polaris.version> <polaris.version>2.1.1.0-SNAPSHOT</polaris.version>
<!-- Dependencies --> <!-- Dependencies -->
<bcpkix-jdk18on.version>1.78.1</bcpkix-jdk18on.version> <bcpkix-jdk18on.version>1.78.1</bcpkix-jdk18on.version>

@ -20,10 +20,12 @@ package com.tencent.cloud.quickstart.caller;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.PolarisCompletableFutureUtils;
import com.tencent.cloud.quickstart.caller.pojo.User; import com.tencent.cloud.quickstart.caller.pojo.User;
import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -34,6 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -229,6 +232,52 @@ public class QuickstartCallerController {
return restTemplate.getForObject(path, String.class); return restTemplate.getForObject(path, String.class);
} }
/**
* Get information of callee with async and delay.
* @param headerMap request headers
* @param delay delay time in milliseconds
* @return information of callee
*/
@GetMapping("/rest-async")
public ResponseEntity<String> restAsync(@RequestHeader Map<String, String> headerMap,
@RequestParam(defaultValue = "1000") long delay) {
String url = "http://QuickstartCalleeService/quickstart/callee/info";
HttpHeaders headers = new HttpHeaders();
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
if (StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())
&& !entry.getKey().contains("sct-")
&& !entry.getKey().contains("SCT-")
&& !entry.getKey().contains("polaris-")
&& !entry.getKey().contains("POLARIS-")) {
headers.add(entry.getKey(), entry.getValue());
}
}
HttpEntity<String> entity = new HttpEntity<>(headers);
PolarisCompletableFutureUtils.runAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(delay);
LOG.info("begin rest");
ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
LOG.info("result: {}", result.getBody());
}
catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) {
LOG.error("HttpClientErrorException: {}", httpClientErrorException.getResponseBodyAsString());
}
catch (InterruptedException e) {
LOG.error("InterruptedException: {}", e.getMessage());
}
catch (Throwable t) {
LOG.error("Throwable", t);
}
});
LOG.info("return ok");
return new ResponseEntity<>("ok", HttpStatus.OK);
}
/** /**
* Get information of callee. * Get information of callee.
* @return information of callee * @return information of callee

Loading…
Cancel
Save