检索组成员时出现 Microsoft Graph 3.0 java.net.SocketTimeoutException

2023-12-03

我最近将我的应用程序升级为:

  • 春季启动:2.4.4
  • 微软图:3.0.0

在升级应用程序时,我遵循了升级指南.

我正在使用以下代码检索组成员:

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 and 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,进而创建一个连接池。由于操作系统管理连接的方式(它们保持打开状态一段时间,因为关闭和打开连接是一项成本高昂的操作),这将导致计算机上的端口耗尽。
在没有更多可用端口后传入的下一个请求会阻塞等待端口释放和连接可用,并最终超时(您看到的异常除外)。

要解决该问题:

  • 确保您的 GraphClient 类在应用程序的整个生命周期中实例化一次
  • 为 getGraphServiceClient 方法实现一些延迟加载,因此它将客户端“缓存”在字段中,并在值不为 null 时返回该客户端,而不是为每次调用创建一个新客户端。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

检索组成员时出现 Microsoft Graph 3.0 java.net.SocketTimeoutException 的相关文章

随机推荐