[soul-admin] [upstreams] [soul-admin] [upstreams] [upstreams] [soul-admin] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] [upstreams] Let’s dig into the source code to see how it works:
Soul-admin UpstreamCheckService#setup() is initialized from db after loading into upstreamMap.
/**
* this is divide http url upstream.
*
* @author xiaoyu
*/
@Slf4j
@Component
public class UpstreamCheckService {
"// use upstream
private static final Map<String, List<DivideUpstream>> UPSTREAM_MAP = Maps.newConcurrentMap();
// Whether to turn on the probe switch
@Value("${soul.upstream.check:true}")
private boolean check;
// The duration of periodic probing is 10 seconds by default
@Value("${soul.upstream.scheduledTime:10}")
private int scheduledTime;
private final SelectorMapper selectorMapper;
private final ApplicationEventPublisher eventPublisher;
private final PluginMapper pluginMapper;
private final SelectorConditionMapper selectorConditionMapper;
/ /...
/** * load Selector configuration */
@PostConstruct
public void setup(a) {
PluginDO pluginDO = pluginMapper.selectByName(PluginEnum.DIVIDE.getName());
if(pluginDO ! =null) {
List<SelectorDO> selectorDOList = selectorMapper.findByPluginId(pluginDO.getId());
// Iterate over the Selector record and place upstream in the corresponding Selector name
for (SelectorDO selectorDO : selectorDOList) {
List<DivideUpstream> divideUpstreams = GsonUtils.getInstance().fromList(selectorDO.getHandle(), DivideUpstream.class);
if(CollectionUtils.isNotEmpty(divideUpstreams)) { UPSTREAM_MAP.put(selectorDO.getName(), divideUpstreams); }}}if (check) {
new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), SoulThreadFactory.create("scheduled-upstream-task".false))
.scheduleWithFixedDelay(this::scheduled, 10, scheduledTime, TimeUnit.SECONDS); }}/ /...
/**
* Submit.
*
* @param selectorName the selector name
* @param divideUpstream the divide upstream
*/
public void submit(final String selectorName, final DivideUpstream divideUpstream) {
if (UPSTREAM_MAP.containsKey(selectorName)) {
UPSTREAM_MAP.get(selectorName).add(divideUpstream);
} else{ UPSTREAM_MAP.put(selectorName, Lists.newArrayList(divideUpstream)); }}/**
* Replace.
*
* @param selectorName the selector name
* @param divideUpstreams the divide upstream list
*/
public void replace(final String selectorName, final List<DivideUpstream> divideUpstreams) {
UPSTREAM_MAP.put(selectorName, divideUpstreams);
}
// Use a timed thread pool for probing
private void scheduled(a) {
if (UPSTREAM_MAP.size() > 0) {
UPSTREAM_MAP.forEach(this::check); }}// Core method to perform checkUrl on Upstream in each selector
private void check(final String selectorName, final List<DivideUpstream> upstreamList) {
List<DivideUpstream> successList = Lists.newArrayListWithCapacity(upstreamList.size());
for (DivideUpstream divideUpstream : upstreamList) {
final boolean pass = UpstreamCheckUtils.checkUrl(divideUpstream.getUpstreamUrl());
if (pass) {
if(! divideUpstream.isStatus()) { divideUpstream.setTimestamp(System.currentTimeMillis()); divideUpstream.setStatus(true);
log.info("UpstreamCacheManager check success the url: {}, host: {} ", divideUpstream.getUpstreamUrl(), divideUpstream.getUpstreamHost());
}
successList.add(divideUpstream);
} else {
divideUpstream.setStatus(false);
log.error("check the url={} is fail ", divideUpstream.getUpstreamUrl()); }}if (successList.size() == upstreamList.size()) {
return;
}
if (successList.size() > 0) {
UPSTREAM_MAP.put(selectorName, successList);
updateSelectorHandler(selectorName, successList);
} else {
UPSTREAM_MAP.remove(selectorName);
updateSelectorHandler(selectorName, null); }}/ /...
}
Copy the code
Here is UpstreamCheckUtils:
public class UpstreamCheckUtils {
// Regular expression to filter out valid IP
private static final Pattern PATTERN = Pattern
.compile("(http://|https://)? (? : (? : [0, 1]? \\d? \\d|2[0-4]\\d|25[0-5])\\.) {3} (? : [0, 1]? \\d? \ \ | 2 d \ \ [0-4] d | 25 [0-5]) : \ \ d {0, 5}");
private static final String HTTP = "http";
/**
* Check url boolean.
*
* @param url the url
* @return the boolean
*/
public static boolean checkUrl(final String url) {
if (StringUtils.isBlank(url)) {
return false;
}
if (checkIP(url)) {
String[] hostPort;
// If HTTP is used
if (url.startsWith(HTTP)) {
final String[] http = StringUtils.split(url, "\ \ \ \ /");
hostPort = StringUtils.split(http[1], Constants.COLONS);
} else {
hostPort = StringUtils.split(url, Constants.COLONS);
}
return isHostConnector(hostPort[0], Integer.parseInt(hostPort[1]));
} else {
returnisHostReachable(url); }}private static boolean checkIP(final String url) {
return PATTERN.matcher(url).matches();
}
private static boolean isHostConnector(final String host, final int port) {
try (Socket socket = new Socket()) {
// use the socket client to connect to upstream
socket.connect(new InetSocketAddress(host, port));
} catch (IOException e) {
// If an exception is thrown, false is returned
return false;
}
return true;
}
// Check whether the domain name is reachable
private static boolean isHostReachable(final String host) {
try {
return InetAddress.getByName(host).isReachable(1000);
} catch (IOException ignored) {
}
return false; }}Copy the code