RubyでKinesis Streamからレコードを取得する処理を書いていたのですが、通信が入れ替わったりして別のShardのShardIteratorが混じってくる現象に悩まされていました。
結論から言うと、AWS-SDKは内部でグローバルなConnection Poolを作ります。親プロセスで1回でもAWS-SDKを使って通信をすると、Forkした後に子供にも内部のConnection Poolがそのまま継承されます。
親で作られたCollectionPool=FDが複数の子供で共有されてしまうので、それぞれのプロセスで通信が混線してしまったという訳です。
解決策としては、子プロセスの最初に次のコードを実行する必要があります。
Seahorse::Client::NetHttp::ConnectionPool.pools.each do |pool| |
AWS-SDKのバージョンがv2.9.5以降であれば次のコードで同じコードが実行されます。
Aws.empty_connection_pools! |
関連チケットです https://github.com/aws/aws-sdk-ruby/issues/1438
他にも使用していたLevelDBやSequelでもForkSafeではないのでそれぞれ対策が必要です。
LevelDBの場合
こんな感じで書き込みが止まってしまいました。
こっちは色々と掃除しても何故か発生してしまうので、親プロセスで使うなという感じ。
#0 0x00007f1e7929a64d in poll () from /lib64/libc.so.6 |
https://github.com/google/leveldb/issues/169#issuecomment-260458097
Sequelの場合
接続を切りましょう
DB.disconnect |
http://www.rubydoc.info/github/jeremyevans/sequel/Sequel%2FDatabase%3Adisconnect
まとめ
ライブラリの中身を気にしながらForkを考えるのは難しい。