spring cloud集成seata报错Read timed out问题解决

spring cloud集成seata报错Read timed out问题解决

问题

最近做项目,需要集成seata实现分布式事务。遇到一个很麻烦的问题,异常能回滚,但是总是测试正常调用时会出现 “ReadTimeOut” 调用超时的异常。异常信息如下:

feign.RetryableException: Read timed out executing POST http://test/test?status=false
	at feign.FeignException.errorExecuting(FeignException.java:213)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:115)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:80)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
	at com.sun.proxy.$Proxy169.test(Unknown Source)
	at com.personal.record.handler.UserHandler.insertUser(UserHandler.java:30)
	at com.personal.record.handler.UserHandler$$FastClassBySpringCGLIB$$5e19999f.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
	...

解决

在网上看了很多方法,试了都不行,于是决定Debug,从源码分析试一试。

通过报错一路追溯,发现是ribben调用时超时报错。
因为之前也配置了ribben的ReadTimedOut参数,但是始终不生效,于是找到ribben的ReadTimedOut注入的位置。

public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) {
        super(lb, clientConfig);
        this.setRetryHandler(RetryHandler.DEFAULT);
        this.clientConfig = clientConfig;
        this.ribbon = RibbonProperties.from(clientConfig);
        RibbonProperties ribbon = this.ribbon;
        this.connectTimeout = ribbon.getConnectTimeout();
        this.readTimeout = ribbon.getReadTimeout();
        this.serverIntrospector = serverIntrospector;
    }
public Integer getReadTimeout() {
        return (Integer)this.get(CommonClientConfigKey.ReadTimeout);
    }
public <T> T get(IClientConfigKey<T> key) {
        return this.config.get(key);
    }
@Override
    public <T> T get(IClientConfigKey<T> key) {
        Object obj = getProperty(key.key());
        if (obj == null) {
            return null;
        }
        Class<T> type = key.type();
        if (type.isInstance(obj)) {
            return type.cast(obj);
        } else {
            if (obj instanceof String) {
                String stringValue = (String) obj;
                if (Integer.class.equals(type)) {
                    return (T) Integer.valueOf(stringValue);
                } else if (Boolean.class.equals(type)) {
                    return (T) Boolean.valueOf(stringValue);
                } else if (Float.class.equals(type)) {
                    return (T) Float.valueOf(stringValue);
                } else if (Long.class.equals(type)) {
                    return (T) Long.valueOf(stringValue);
                } else if (Double.class.equals(type)) {
                    return (T) Double.valueOf(stringValue);
                } else if (TimeUnit.class.equals(type)) {
                    return (T) TimeUnit.valueOf(stringValue);
                }
                throw new IllegalArgumentException("Unable to convert string value to desired type " + type);
            }
             
            throw new IllegalArgumentException("Unable to convert value to desired type " + type);
        }
    }
protected Object getProperty(String key) {
        if (enableDynamicProperties) {
            String dynamicValue = null;
            DynamicStringProperty dynamicProperty = dynamicProperties.get(key);
            if (dynamicProperty != null) {
                dynamicValue = dynamicProperty.get();
            }
            if (dynamicValue == null) {
                dynamicValue = DynamicProperty.getInstance(getConfigKey(key)).getString();
                if (dynamicValue == null) {
                    dynamicValue = DynamicProperty.getInstance(getDefaultPropName(key)).getString();
                }
            }
            if (dynamicValue != null) {
                return dynamicValue;
            }
        }
        return properties.get(key);
    }
String getDefaultPropName(String propName) {
        return getNameSpace() + "." + propName;
    }
@Override
	public String getNameSpace() {
		return propertyNameSpace;
	}
public static final String DEFAULT_PROPERTY_NAME_SPACE = "ribbon";
private String propertyNameSpace = DEFAULT_PROPERTY_NAME_SPACE;

通过Debug及源码分析,程序注入的一直是默认值:1000,配置未注入。而注入ribben的ReadTimedOut的方式是读取 “ribben.ReadTimedOut”配置。在之前的配置中,此项配置一直放在yml文件中:

ribbon:
  ReadTimeout: 10000
  ConnectTimeout: 10000

之后将此项配置放入properties配置文件中

ribbon.ReadTimeout = 10000
ribbon.ConnectTimeout = 10000

重启项目再次调用,发现配置正常注入,不再报超时错误。


版权声明:本文为Junglefisher原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。