概要
2018年7月18日に突然APNsを使用したiOSのpushが届かなくなりました。
原因の調査を行なったのでまとめます。
同じ境遇に遭遇した方のお役に立てば幸いです。
原因
pushが飛ばなくなった原因は、AppleのAPNsリクエストの仕様変更によるものだと思われます。
HTTP2のRFCには、すべての擬似ヘッダーが通常ヘッダーよりも先に書かれていなければならない(MUST)と記載があるのですが、この制約の強制をAPNsへ適用したことにより、制約に準拠していないリクエストが通らなくなったことがpushが送信できなくなった原因でした。
HTTP2のRFCが日本語訳されたものもあるので、こちらも参考にしてみてください。
https://summerwind.jp/docs/draft-ietf-httpbis-http2-14#section8-1-2-1
対策
リクエストヘッダー内で、擬似ヘッダーを通常ヘッダーより先に記載するように修正すればリクエストが通るようになります。
私の場合、apnoticというgemを使用していました。
apnoticを使用している場合は、apnotic内で使用しているnet-http2
のバージョンを0.18.0
以上にすれば直ります。
詳細はこのissueを見てください。
余談
net-http2
gemを使用している場合、このgem内で
end.tap { |t| t.abort_on_exception = true }
https://github.com/ostinelli/net-http2/blob/1513fb7cb661bfcc6648ef31fbc3b66095dacc51/lib/net-http2/client.rb#L122
という記載があり、スレッドの外に例外を送った場合は、Rubyインタプリタごと落ちてしまうようになっていました。
そのためsidekiqなどの非同期ワーカーでpushを送信していると、Socket was remotely closed
というログを残しsidekiqのワーカーごと落ちてしまいます。
Rubyインタプリタ落ちてしまうのを防ぎたい場合は、下記のようにerrorイベントを拾うコールバックを設定してください。
client.on(:error) { |exception| puts "Exception has been raised: #{exception}" }
詳しくはREADMEを参考にしてください。