概要
Zencoder は、ほとんどのお客様にとって重要なソフトウェア依存関係です。また、100%の稼働率を目指していますが、Zencoderに接続できない場合があります。
これが起こり、Zencoder がダウンすると、アプリケーションは通常 Zencoder から '503 Service Unavailable' レスポンスを取得しますが、別のエラー (500 など) が発生する可能性があります。API のレート制限を超過した場合は、'403' レート制限超過レスポンスが得られます。
良いニュース:ビデオエンコーディングは非同期プロセスであるため、ダウンタイムや可用性に関連する問題が発生しないようにアプリケーションを構築できます。これを行うと、最悪のシナリオは、ジョブが少し長くかかるということです。しかし、エラーは発生しません。これを行うことを強くお勧めします。
より強く言えば、信頼性を重視する場合は、Zencoder、または統合する重要なAPIに対して、この統合アプローチに従う必要があります。
- 当社のサービスは、アップストリームプロバイダー(アマゾンウェブサービスなど)の問題の影響を受ける可能性があります
- 一時的なダウンタイムを必要とするシステムメンテナンスを実行する必要が生じることがあります。
- API レート制限を超過しました
- 等
信頼性の高いアプリ統合
- プライマリロケーションへのアップロードが失敗した場合に備えて、セカンダリ URLをバックアップとして含めます。
- Zencoder から失敗したレスポンスコード (基本的に、200 または 201 以外のもの) を取得しても、ジョブが失敗することはありません。レスポンスコード 503 は、動画を処理できないことを意味するものではありません。これは、Zencoder が一時的に利用できないことを意味します。
- Zencoder に接続しようとして接続エラーが発生した場合は、同じことをしてください。
- 同様に、API リクエストをタイムアウトでラップします。30 秒のタイムアウトをお勧めします。Zencoder は通常 1 秒未満で応答するため、通常 30 秒は十分な時間です。
- これらの 3 つのケースすべて (失敗したレスポンスコードを取得した場合、接続できない、API リクエストがタイムアウトした場合)、ジョブに「保留中」フラグを付けます。
- 定期的に、 '保留中のジョブを再送信します' 州。たとえば、cronを使用してこれを毎分行うことができます。
ジョブが再送信されると、すべてが正常に動作します。この方法では、ジョブの送信に失敗しても、アプリケーションまたはユーザーに問題を引き起こすのではなく、ジョブにかかる時間が少し長くなります。
擬似コード
さて、これは擬似コードではありません-それはRubyです。しかし、Rubyはかなり読みやすいです。
- これらの列を含む Videos テーブルを想像してください。(明らかに、Zencoder ジョブ ID と Zencoder 出力ファイル ID を格納するカラムなど、より多くのカラムがあります)。
create_table :videos do |t| t.string :state t.integer :lock_version t.index :state end
- ビデオには、次の状態のステートマシンを含める必要があります。
- 保留中 (Zencoder にまだ提出されていません)
- 提出 (現在 Zencoder に提出中)
- トランスコーディング (Zencoder に正常に送信)
- 終了 (Zencoder はトランスコーディングを完了し、ジョブが完了しました)
- 失敗しました(Zencoderはビデオをトランスコードできませんでした)
- 新しい動画が取り込まれたら、動画を「送信中」' の状態で保存し、バックグラウンドジョブをトリガーして動画を Zencoder に送信します。
# got a new video! video = Video.new(params) video.state = "submitting" video.save! submit_to_zencoder(video)
あなたは本当にsubmit_to_zencoderメソッドをバックグラウンドする必要があります。Ruby では、delayedJob を使用すると、次のようになります。
delay.submit_to_zencoder(video)
しかし、
submit_to_zencoder(video)
例を挙げてメソッドに固執します。 submit_to_zencoder
この関数は次のようになります。これは、バックグラウンドで非同期で実行する必要があります。def submit_to_zencoder(video) begin response = Zencoder::Job.create(attributes, :timeout => 30_000) if response.code == 201 video.state = "transcoding" else video.state = "pending" end video.save! # Rescue any connection error. Our plugin abstracts these as # Zencoder::HTTPError. # # If you're not using the Zencoder plugin, this includes things # like Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::ECONNREFUSED, # Errno::EHOSTDOWN, and SocketError. rescue Timeout::Error, Zencoder::HTTPError video.state = "pending" video.save! end end
- 毎分、例えば、毎分-「' 保留中」のジョブを再送信してみてください。
def resubmit_pending_jobs Video.where(:state => "pending").find_each do |video| begin video.state = "submitting" video.save! submit_to_zencoder(video) rescue ActiveRecord::StaleObjectError end end end
また、ビデオテーブルに 'lock_version' 列を追加することで、楽観的ロックを導入します。つまり、
Video.find
クエリととの間でレコードが更新された場合video.save
、Zencoder にジョブを送信しません。これにより、ジョブが誤ってZencoderに2回送信されるのを防ぐことができます。悲観的、データベースロック、または他のロック方法を使用して、同じことを達成することができます。それは簡単だ...
すべてのことを考慮すると、これは Zencoder とアプリケーション間の統合の信頼性を100%保証するための非常にシンプルなアプローチです。これは、単純にジョブを送信するだけではありません。ただし、不定期のタイムアウト、Zencoder での予期しないダウンタイム、またはスケジュールされたメンテナンスなど、何が起こっても、アプリは確実に実行されます。