Apache HttpClient の DefaultHttpRequestRetryHandler は ConnectTimeoutException のときはリトライしない

Apache HttpClient はデフォルトで3回リトライする機能を持っています。しかし、コネクションタイムアウト (ConnectTimeoutException) のときはリトライしません。すべてドキュメントに書いてあることなんですが、そのあたりを調べたときのメモ。

※以下は Apache HttpClient 4.4.1 で調べています。

HttpClientBuilder#setRetryHandler でハンドラを設定せずに HttpClient を生成すると、デフォルトで DefaultHttpRequestRetryHandler が使われます。

以下、HttpClientBuilder#build から抜粋。

if (!automaticRetriesDisabled) { // automaticRetriesDisabled は デフォルトで false
    HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
    if (retryHandlerCopy == null) {
        retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE; // INSTANCE は new DefaultHttpRequestRetryHandler() で初期化されている
    }
    execChain = new RetryExec(execChain, retryHandlerCopy);
}

以下、DefaultHttpRequestRetryHandler のドキュメントから抜粋。

DefaultHttpRequestRetryHandler (Apache HttpClient 4.4.1 API)

Create the request retry handler with a retry count of 3, requestSentRetryEnabled false and using the following list of non-retriable IOException classes: InterruptedIOException, UnknownHostException, ConnectException, SSLException

余談ですが、最初、ここの non-retriablenon-retrieval に読み間違えて、全然見当違いな解釈をしていたことは内緒です。で、デフォルトコンストラクタを呼び出すと、リトライ不可能な IOException として以下が設定されるようです。

  • InterruptedIOException
  • UnknownHostException
  • ConnectException
  • SSLException

以下、DefaultHttpRequestRetryHandler#retryRequest からリトライ処理を抜粋。

if (this.nonRetriableClasses.contains(exception.getClass())) {
    return false;
} else {
    for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
        if (rejectException.isInstance(exception)) {
            return false;
        }
    }
}

この this.nonRetriableClasses に上記4つのクラスが設定されています。ConnectTimeoutExceptionInterruptedIOException のサブクラスなので、retryRequestfalse を返すことになります。

したがって、ハンドラを設定していない HttpClient では、コネクションタイムアウトのときにリトライしません。

(参考) Chapter 1. Fundamentals

  • 1.5.3. Automatic exception recovery
  • 1.5.4. Request retry handler

Windows 7 / 8.1 仮想環境

必要に迫られて構築したときに調べたメモ。

Free Virtual Machines from IE8 to MS Edge - Microsoft Edge Development

IE8 から Microsoft Edge までの Windows 仮想環境をダウンロードできる。
組み合わせは以下の通り。(2016/12/08 時点)

仮想環境の形式は VirtualBox, Vagrant, HyperV, VMWare から選択する。今回は IE11 on Win8.1 / Vagrant を利用。zip をダウンロードして展開する。

> vagrant init <box-name> # box-name は box のファイル名を指定

Vagrantfile に以下を設定する。

config.vm.provider "virtualbox" do |vb|
    vb.gui = true
end
config.vm.guest = :windows
config.vm.communicator = "winrm"
config.vm.network :forwarded_port, guest: 3389, host: 3389

仮想マシン起動。

> vagrant up

起動が完了すると、VirtualBox のコンソールが起動する。とりあえず日本語化する。

プロキシ

日本語化は、Windows Update 経由で Language Pack をダウンロードするようなので、プロキシ環境の場合はプロキシを設定する。

  1. Windows キー > Apps > PC settings
  2. Network > Proxy
  3. Use a proxy server を On

日本語化

  1. Windows キー > Apps > PC settings
  2. Time and language > Region and language
  3. Country or region で Japan を選択
  4. Languages の Add a language で「日本語」を追加
  5. 日本語をクリック > Options
  6. Language options の Language Pack をダウンロード
  7. 日本語をクリック > Set as primary
  8. English を Remove

ついでに Time and language の Date and time で Time zone を変更する。

サインアウト > サインインで、日本語化が適用される。

JJUG CCC 2016 Fall に行ってきた

JJUG CCC 2016 Fall に行ってきました。簡単に所感をまとめます。

[CCC2016Fall]Be a great engineer! #jjug_ccc #ccc_a1 - Speaker Deck

  • 「こんなセッションを聞きに来てる時点でダメ」とのこと
  • 技術の本質を考える
  • 適材適所で使い分ける
  • 技術には必ずニーズが伴う (解決したい課題はなにか)
  • 技術的に優れていてもそれが正解とは限らない

他所のとある現場で、流行りの技術を使おうとして半ば強引に某フレームワークを採用しているんじゃないかと思えるようなケースを見たことがあります。そのシステムでそのフレームワークを使う必要があるのかと疑問ではありましたが、自分の考えにイマイチ自信を持つことができませんでした。
そういう意味で、このセッションの話を聴いて自分の考えは概ね間違ってないなと思えた気がします。いきなり「こんなセッションを聞きに来てる時点でダメ」とか言われてお茶吹きそうになりましたが、いい話が聴けてよかったです。

SpringはどうやってDIしているのか? #jjug_ccc - Speaker Deck

とにかくひとが多くて、改めて Spring の勢いを感じました。Spring のコードリーディングの話はたまに聴くけど、毎回勉強せねばって思う...。

メンバーのスキルアップ、どうしてる? − Java 100本ノックで新加入メンバーを鍛えてみた −

  • 回答 -> PR -> レビュー のサイクル
  • 教える側も本質を正しく理解していないといけない
  • アンチパターンには名前をつけるとよい
  • 「あなたが書いたコードはコピペであってもあなたのもの」
    • 自分がコードを書くところは自分の責任

Oracle のベンダー資格あたりも入門として使えそうな気がするけど、Java 100本ノックはより実践的な内容っぽいし、レビューし易いというのがメリットな気がします。

どうしようJUnit5 - Speaker Deck

  • この日、最も聴きたかったセッション
  • JUnit4 と JUnit5 の互換性はない (別のフレームワーク)
  • 基本的な機能は名前やパッケージが変わった程度
  • assertThat がなくなった (hamcrest を入れれば使える)
  • @Enclosed -> @Nested
    • @BeforeEach を使えばネストクラス間で初期化処理を共通化できそう
  • @DisplayName でテストに名前を付けることができる
    • メソッド名を日本語で書いてた日々に別れを告げる...

既存のテストを JUnit4 から移行する必要はなく、JUnit5 の正式リリース以降、新しくテストを書く場合に採用する感じでよさそう。
あと、テストメソッドの実行順序を制御する機能(@FixMethodOrder)があることを初めて知りました...。というか、実行順序を制御しないといけないケースに遭遇したことがないし、そもそも実行順序に依存するのはユニットテストとして NG だと思ってました。が、JUnit をシナリオテストで使うケースがあるんですね、なるほど。
現時点で自分のやりたいことは JUnit4 + JMockit でひと通りはできていて、JUnit5 ならそれがもう少し簡潔にできるのかなという印象。ただ、ぶっちゃけ Runner とか Rule とか Parameterized とか Theory とか JUnit の機能をまだ全然使いこなせていないのでもっと勉強が必要です...。

JPA と DDD の関係で僕が思っていること - Qiita

その他

CCCは7回目の参加になりますが、昔に比べて参加者が格段に増えて規模も大きくなりました。その分、セッション数も増えてどれを聴こうか迷います。あと、マスクがノベルティとして配布されてたけど、大人数が集まる場ではとてもよいですね。ありがたや。

その他の資料 (把握してる分のみ)

(2016/12/06 追記) ここに資料まとまってた。

github.com

妻を愛してる IT エンジニアの件

【その2】妻・夫を愛してるITエンジニア Advent Calendar 2016 - Adventar の5日目です。枠が空いてたので書きます!

結婚してもうすぐ6年になります。その間、2人の子供に恵まれました。夫婦の仲は以前と変わらずまだまだアツアツです。ぐへへ。

妻もITエンジニアをやっています。というか同じ会社の同期です。ただ、同じ会社と言っても部署は違うためやっている仕事は全然違います。私は Web アプリ開発がメインですが、妻は BI やデータ解析などをやっています。なので、仕事の悩みがイマイチ共有できないことがあります。(お互いにアドバイスくらいはできるけど)

あと、保育園では何かと資料作りが必要になることがあり、妻は日頃鍛えた Excel 力を発揮しています。

同じ業界にいることもあり、プロジェクトが炎上して帰りが遅くなったり休出になってもいろいろ察して理解してくれるので助かります。逆に、時短勤務である妻の仕事が忙しかったりミーティングや飲み会に参加するようなときには私が保育園の送迎をやったりします。

共働きなのでお互い助け合ってバランスを取ることが大事です。もちろん家事は分担します。家事は「手伝うもの」ではなく「分担するもの」です。

kntmr.hatenablog.com

妻はあまり勉強会やセミナーに行くことはないのですが、私が平日の夜や休日に勉強会に行きたいときは、基本的に OK してくれます。ただし、保育園の行事などが重なる場合にはそちらを優先します。なので、勉強会の資料をあとから公開していただけるのはとても助かります...!ありがたい。

価値観の違いが夫婦仲の問題になる話をしばしば聞きます。私は、価値観 ≒ 個性 と捉えているため、そこは違っていて当たり前と考えています。価値観が違うからと言ってパートナーとすれ違うのはとても勿体ないことです。長い時間をともに過ごすわけなので、お互いに認め合って譲り合って、楽しく充実した時間を過ごしたいものです。

しかし、妻はよくこんな自分と結婚したなぁと、ふと思うことがあります。そんな妻に圧倒的感謝🙏ぐへへ。

TortoiseSVN で Compare revisions するときはリビジョンの選択範囲に注意する

自戒を込めて。

例えば、r123 ~ r130 でコミットしたファイルを抽出する場合。
単純にヒストリーの r123 ~ r130 を範囲選択して Compare revisions すると、r123 でコミットしたファイルは含まれない。(当然と言えば当然...)

あるリビジョンの差分ファイルを取得する場合は『目的のリビジョン』と『1つ前のリビジョン』を選択する。

したがって、r123 でコミットしたファイルを含める場合は r122 から選択して Compare revisions すること。

Spring Day 2016 に行ってきた

Spring Day 2016 に行ってきました。簡単に所感をまとめます。
いくつかの資料は公式サイトで公開されています。

springday2016.springframework.jp

  • Spring 5.0 では JUnit 5 が標準になる模様
    • JUnit 4 ⇔ 5 は少しギャップがある気がするので個人的には気になるところ
  • Reactive (Mono/Flux)
  • フレームワーク移行 (Struts/Seasar -> Spring)
    • 現行システムの品質(実装ポリシー)で苦労するケースが多い印象
    • 何かしらのポリシーに従っていれば、(部分的にでも)自動化できるかもしれない
    • 開発当初にアーキテクチャや実装ポリシーを固めることが重要か
    • 特に Spring はレイヤ構成でアーキテクチャを統一しやすい (@Controller, @Service, @Repository)
  • Spring Boot は Microservice やスケールアウトが必要なシステムに適している
    • サービスをどう分割するか、冗長なAPIをどう再構成するか
    • RESTful API 開発における API ドキュメントの自動生成
      • Spring REST Docs, Springfox, Swagger
    • 各サービスのプロパティ管理やログ収集の話など
      • Spring Cloud Config, Logstash, Elasticsearch, Kibana, ...
    • spring-boot-starter-cache
  • Spring Initializr カスタマイズ
    • メンバーの開発環境が簡単に構築できてよさそう

個人的にはフレームワーク移行について各社の事例が聞けて参考になりました。アーキテクチャを考えるときにレイヤを意識することが大事だなと。
あと、ドキュメント自動生成。Swagger はちょっと取っ付き難いイメージがあるんですが、その点、Spring REST Docs は手軽でよさそうな気がします。

djUnit を Eclipse 4.5 (mars) と Maven2 で使えるようにする

djUnit 自体、2011年頃から更新されていないため、もはや需要がないかもしれませんが、必要に迫られて調べました。

Eclipse 4.5 (mars)

Eclipse 4.x 以降ではプラグインの仕組みが変更されているようで、古い形式のプラグインが動作しません。よって、古い形式のプラグインを動作させるための Eclipse プラグインをインストールする必要があります。

  1. Help > Install New Software…
  2. リポジトリhttp://download.eclipse.org/eclipse/updates/4.5 を追加
  3. Eclipse Tests, Tools, Examples, and Extras
    Eclipse 2.0 Style Plugin Support をチェックしてインストール

djUnit プラグインをインストール。

  1. ダウンロードサイト から jp.co.dgic.eclipse.jdt.djunit_3.5.x_0.8.6.zip をダウンロード
  2. 展開して作成されたフォルダを Eclipse の plugins フォルダにコピー
  3. plugin.xml の plugin > requires に記載されている
    <import plugin="org.eclipse.core.boot"/>コメントアウト

Maven2

pom.xmlJUnit, djUnit, asm, oro の依存関係を追加。(詳細は省略)

ここでは Maven Surefire Plugin を使用します。pom.xml に以下の設定を追加。

<build>
  <plugins>
    <plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <configuration>
        <argLine>-Djava.system.class.loader=jp.co.dgic.testing.common.DJUnitClassLoader -Djp.co.dgic.eclipse.virtualmock.usevirtualmock=true -Djp.co.dgic.eclipse.coverage.usecoverage=false -Djp.co.dgic.eclipse.project.source.dir=${project.build.sourceDirectory}</argLine>
      </configuration>
    </plugin>
  </plugins>
</build>

とりあえず、手元の環境で $ mvn test してテストがパスするようになりました。

余談

テストコードから getClass().getResource(fileName) でファイルを読み込む場合、テストクラスと同じ階層にファイルを配置すると Maven2 からテストを実行した際に正常に読み込まれません。src/main/resources 下に同様のパッケージ階層を作成してファイルを配置する必要があります。
または、ClassLoader.getSystemResourceAsStream("foo/bar/filename") でパッケージを指定してファイルを読み込みます。