以下はconnectTimeout
の設定に関するものです。
ケース - 未知のホスト
あなたが到達できないホスト(例:http://blablablabla/v1/timeout
)を持っているなら、あなたはできるだけ早くUnknownHostException
を受け取ることになります。 AbstractPlainSocketImpl :: connect() :: !addr.isUnresolved() :: throw UnknownHostException
タイムアウトなし。ホストはInetAddress.getByName(<host_name>)
を使用して解決されます。
ケース - できるだけ早くConnection refused: connect
- 未知のポート
あなたが到達可能であるが、何の接続は行われないことができますホストを持っている場合は、あなたはConnectException
を受けます。これは、DualStackPlainSocketImpl :: socketConnect()
から呼び出されるネイティブメソッドDualStackPlainSocketImpl :: static native void waitForConnect(int fd, int timeout) throws IOException
で発生するようです。タイムアウトは尊重されません。
プロキシ?プロキシが使用されている場合、状況が変化する可能性があります。到達可能なプロキシを持っていると、タイムアウトが発生する可能性があります。
関連する質問チェックthis answerこれはあなたが遭遇した場合に関連しています。
複数のIPアドレスにマップされた同じドメインを持つDNSラウンドロビンは、クライアントが見つかるまで各IPに接続します。したがって、connectTimeout()
は、動作していないリストの各IPに対して独自のペナルティを追加します。詳細についてはthis articleをお読みください。
結論connectTimeout
を取得する場合は、独自のリトライロジックを実装するか、プロキシを使用する必要があります。
テストconnectTimeout
あなたはタイムアウトを取得するため、完成からのソケット接続を防ぐエンドポイントを持つのさまざまな方法のthis answerを参照することができます。ソリューションを選択すると、バンプブーツで統合テストを作成し、実装を検証することができます。これは、readTimeout
をテストするために使用される次のテストに似ています。この場合、ソケット接続を妨げるURLに変更することができます。
テストreadTimeout
readTimeout
が最初、従ってサービスをアップする必要がある接続である必要がテストするために。次に、各要求に対して大きな遅延を伴う応答を返すエンドポイントを提供することができる。
次は、統合テストを作成するために、春ブートで行うことができます
1.テスト
@RunWith(SpringRunner.class)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { RestTemplateTimeoutConfig.class, RestTemplateTimeoutApplication.class }
)
public class RestTemplateTimeoutTests {
@Autowired
private RestOperations restTemplate;
@LocalServerPort
private int port;
@Test
public void resttemplate_when_path_exists_and_the_request_takes_too_long_throws_exception() {
System.out.format("%s - %s\n", Thread.currentThread().getName(), Thread.currentThread().getId());
Throwable throwable = catchThrowable(() ->
restTemplate.getForEntity(String.format("http://localhost:%d/v1/timeout", port), String.class));
assertThat(throwable).isInstanceOf(ResourceAccessException.class);
assertThat(throwable).hasCauseInstanceOf(SocketTimeoutException.class);
}
}
2.設定RestTemplate
@Configuration
public class RestTemplateTimeoutConfig {
private final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(getRequestFactory());
}
private ClientHttpRequestFactory getRequestFactory() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(TIMEOUT);
factory.setConnectTimeout(TIMEOUT);
factory.setConnectionRequestTimeout(TIMEOUT);
return factory;
}
}
を作成します。 3.テストスターが起動したときに実行されるSpring Bootアプリ
@Configuration
public class RestTemplateTimeoutConfig {
private final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
// consider that this is the existing RestTemplate
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
// this will change the RestTemplate settings and create another bean
@Bean
@Primary
public RestTemplate newRestTemplate(RestTemplate restTemplate) {
SimpleClientHttpRequestFactory factory =
(SimpleClientHttpRequestFactory) restTemplate.getRequestFactory();
factory.setReadTimeout(TIMEOUT);
factory.setConnectTimeout(TIMEOUT);
return restTemplate;
}
}
を設定し、既存のRestTemplate
RequestConfigを使用して新しいRestTemplateをRestTemplate
設定を構成したTS
@SpringBootApplication
@Controller
@RequestMapping("/v1/timeout")
public class RestTemplateTimeoutApplication {
public static void main(String[] args) {
SpringApplication.run(RestTemplateTimeoutApplication.class, args);
}
@GetMapping()
public @ResponseStatus(HttpStatus.NO_CONTENT) void getDelayedResponse() throws InterruptedException {
System.out.format("Controller thread = %s - %s\n", Thread.currentThread().getName(), Thread.currentThread().getId());
Thread.sleep(20000);
}
}
代替方法
をMockRestServiceServer
にRestTemplate
と偽装して、なぜリクエストファクトリを置き換えないのですか。したがって、RestTemplate
の設定はすべて置き換えられます。したがって、タイムアウトテストのために実際のアプリケーションを使用することは、ここでは唯一のオプションかもしれません。
注:も確認してくださいthis article約RestTemplate
コンフィグレーションにはタイムアウトコンフィグレーションも含まれています。
タイムアウトを設定せずに接続できますか? – Vaibs
@ Vaibs、テスト目的のための番号私は外部Webサービスを開始しませんでした。指定されたタイムアウトは機能しません。 – Easy2DownVoteHard2Ans
自分の環境でコードをテストしただけです。そのうまく動作します。あなたのサービスはこれをテストするべきです。これを達成するために、私の提案は接続タイムアウト値を最小にすることです。 10msに変更してください。 – Vaibs