检索组成员时发生Microsoft Graph 3.0 java.net.SocketTimeoutException
我最近将我的应用程序升级到:
- Spring Boot:2.4.4
- Microsoft-graph:3.0.0
升级应用程序时,我遵循了upgrade guide。
我使用以下代码检索组成员:
public void getGroupMembersWithDevices(final IGroup group) {
List<IUser> users = this.userService.getAllUsersWithDevices();
List<IUser> groupUsers = new ArrayList<>();
DirectoryObjectCollectionWithReferencesPage directoryObjectCollectionWithReferencesPage = this.graphClient
.getGraphServiceClient()
.groups(group.getGroupId().toString())
.members()
.buildRequest()
.select("Id")
.top(999)
.get();
while (directoryObjectCollectionWithReferencesPage != null) {
final List<DirectoryObject> directoryObjects = directoryObjectCollectionWithReferencesPage.getCurrentPage();
List<IUser> usersWithDevices = users.stream().filter(
one -> directoryObjects.stream().anyMatch(two -> UUID.fromString(two.id).equals(one.getUserId())))
.collect(Collectors.toList());
if (usersWithDevices.size() > 0) {
groupUsers.addAll(usersWithDevices);
users.removeAll(usersWithDevices);
}
final DirectoryObjectCollectionWithReferencesRequestBuilder nextPage =
directoryObjectCollectionWithReferencesPage.getNextPage();
if (nextPage == null) {
break;
} else {
directoryObjectCollectionWithReferencesPage = nextPage.buildRequest().get();
}
}
group.setUsers(groupUsers.stream().collect(Collectors.toSet()));
}
IUser
和IDevice
是创建的自定义模型。
com.microsoft.graph.core.ClientException: Error executing the request
at com.microsoft.graph.http.CoreHttpProvider.sendRequestInternal(CoreHttpProvider.java:388)
at com.microsoft.graph.http.CoreHttpProvider.send(CoreHttpProvider.java:214)
at com.microsoft.graph.http.CoreHttpProvider.send(CoreHttpProvider.java:191)
at com.microsoft.graph.http.BaseCollectionRequest.send(BaseCollectionRequest.java:102)
at com.microsoft.graph.http.BaseEntityCollectionRequest.get(BaseEntityCollectionRequest.java:78)
at com.app.intune.util.GroupUtil.getGroupMembersWithDevices(GroupUtil.java:128)
at com.app.intune.ScheduleInventory.scheduleGetInventory(ScheduleInventory.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:95)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at sun.security.ssl.InputRecord.readFully(Unknown Source)
at sun.security.ssl.InputRecord.read(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at okio.Okio$2.read(Okio.java:140)
at okio.AsyncTimeout$2.read(AsyncTimeout.java:237)
at okio.RealBufferedSource.indexOf(RealBufferedSource.java:358)
at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:230)
at okhttp3.internal.http1.Http1ExchangeCodec.readHeaderLine(Http1ExchangeCodec.java:242)
at okhttp3.internal.http1.Http1ExchangeCodec.readResponseHeaders(Http1ExchangeCodec.java:213)
at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.java:115)
at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:94)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:43)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at com.microsoft.graph.httpcore.RedirectHandler.intercept(RedirectHandler.java:137)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at com.microsoft.graph.httpcore.RetryHandler.intercept(RetryHandler.java:176)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at com.microsoft.graph.httpcore.AuthenticationHandler.intercept(AuthenticationHandler.java:59)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at com.microsoft.graph.httpcore.TelemetryHandler.intercept(TelemetryHandler.java:69)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
at okhttp3.RealCall.execute(RealCall.java:81)
at com.microsoft.graph.http.CoreHttpProvider.sendRequestInternal(CoreHttpProvider.java:385)
... 20 more
更新1:
下面为创建图形客户端和设置代理创建的类:
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.azure.core.http.ProxyOptions;
import com.azure.core.http.netty.NettyAsyncHttpClientBuilder;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import com.microsoft.graph.requests.GraphServiceClient;
@Component
public class GraphClient {
private String clientId;
private String clientSecret;
private List<String> scopes;
private String tenantId;
@Autowired
BasicConfiguration configuration;
@Autowired
IntuneConfig intuneConfig;
@PostConstruct
public void init() {
this.clientId = this.configuration.getClientId();
this.clientSecret = this.configuration.getSecretKey();
this.scopes = Arrays.asList(this.configuration.getScope());
this.tenantId = this.configuration.getTenant();
}
@SuppressWarnings({ "rawtypes" })
public GraphServiceClient getGraphServiceClient() {
final ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
.clientId(this.clientId).clientSecret(this.clientSecret).tenantId(this.tenantId)
.httpClient(
new NettyAsyncHttpClientBuilder()
.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress(
this.intuneConfig.getProxyHost(), this.intuneConfig.getProxyPort())))
.build())
.build();
final TokenCredentialAuthProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(this.scopes,
clientSecretCredential);
final GraphServiceClient graphClient = GraphServiceClient.builder()
.authenticationProvider(tokenCredentialAuthProvider).buildClient();
return graphClient;
}
}
更新2:更新GraphClient类以检索GraphServiceClient实例。该实例仅创建一次。
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.azure.core.http.ProxyOptions;
import com.azure.core.http.netty.NettyAsyncHttpClientBuilder;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import com.microsoft.graph.requests.GraphServiceClient;
@Component
public class GraphClient {
private String clientId;
private String clientSecret;
private List<String> scopes;
private String tenantId;
@SuppressWarnings("rawtypes")
private static GraphServiceClient graphClient;
@Autowired
BasicConfiguration configuration;
@Autowired
IntuneConfig intuneConfig;
@PostConstruct
public void init() {
this.clientId = this.configuration.getClientId();
this.clientSecret = this.configuration.getSecretKey();
this.scopes = Arrays.asList(this.configuration.getScope());
this.tenantId = this.configuration.getTenant();
}
@SuppressWarnings({ "rawtypes" })
public GraphServiceClient getGraphServiceClient() {
if (GraphClient.graphClient == null) {
final ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
.clientId(this.clientId).clientSecret(this.clientSecret).tenantId(this.tenantId)
.httpClient(
new NettyAsyncHttpClientBuilder()
.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress(
this.intuneConfig.getProxyHost(), this.intuneConfig.getProxyPort())))
.build())
.build();
final TokenCredentialAuthProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(this.scopes,
clientSecretCredential);
final GraphServiceClient client = GraphServiceClient.builder()
.authenticationProvider(tokenCredentialAuthProvider).buildClient();
GraphClient.graphClient = client;
}
return GraphClient.graphClient;
}
}
解决方案
正在为每个调用实例化GraphServiceClient。这又会为每个GraphServiceClient实例化一个OkHttpClient,进而创建一个连接池。由于OS管理连接的方式(它们在一段时间内保持打开,因为关闭和打开连接是一项代价高昂的操作),这将导致计算机上的端口耗尽。
没有更多端口可用后传入的下一个请求,挡路等待端口释放并连接可用,最终超时,出现您看到的异常。
要解决该问题,请执行以下操作:
- 确保在应用程序的整个生命周期中实例化一次GraphClient类
- 为getGraphServiceClient方法实现一些延迟加载,以便它在字段中缓存客户端(&q;)并返回该值(如果值不为NULL),而不是为每个调用创建一个新值。
相关文章