Upgrade to Pro — share decks privately, control downloads, hide ads and more …

動画の視聴ログの実装について

Kohei Hasegawa
February 08, 2019
2.6k

 動画の視聴ログの実装について

2019年2月8日にTECH PLAY Shibuya で行われた [ スタディサプリ/Quipper Product Meetup #2 〜64万人が利用する教育サービスを作る技術と育てる技術〜 ] のイベント登壇資料です。

Kohei Hasegawa

February 08, 2019
Tweet

Transcript

  1. #sapurimeetup 動画の視聴ログの実装について Agenda | 01 02 03 04 05 自己紹介

    動画の視聴ログとは? サーバに対してどうデータを送信するか クライアント側でデータをロストさせないようにする まとめ 2
  2. #sapurimeetup 動画の視聴ログの実装について 3 @banyan / Kohei Hasegawa Engineering Manager 2013年5月に

    join。2015年にリクルートに買収された後は受験サプリからスタ ディサプリへの移行プロジェクトに関わる。その後先生用のサービスをリニューア ルして現在は生徒用のサービスのリニューアルに関わっている
  3. #sapurimeetup 動画の視聴ログの実装について Before: 1. あるユーザが動画を見始める: [[0, 0]] 2. そのまま視聴し続けた a.

    20秒毎に position を送信するため [[0, 20]] -> [[0, 40]] -> [[0, 60]] と 更新される 3. そして 121秒経った時に stop を押した: [[0, 121]] 4. 9秒後に seek して視聴を再開した: [[0, 121], [130, 130]] 11
  4. #sapurimeetup 動画の視聴ログの実装について Before: 1. あるユーザが動画を見始める: [[0, 0]] ← video_start 2.

    そのまま視聴し続けた a. 20秒毎に position を送信するため [[0, 20]] -> [[0, 40]] -> [[0, 60]] と 更新される← video_update 3. そして 121秒経った時に stop を押した: [[0, 121]] ← video_stop 4. 9秒後に seek して視聴を再開した: [[0, 121], [130, 130]] ← video_start 13
  5. #sapurimeetup 動画の視聴ログの実装について 理想的なケース > video_start # => [[0, 0]] video_update

    # => [[0, 20]] video_stop # => [[0, 20]] video_start # => [[0, 20], [30, 30]] # seek forward video_update # => [[0, 20], [30, 50]] video_update # => [[0, 20], [30, 60]] video_stop 15
  6. #sapurimeetup 動画の視聴ログの実装について 理想的なケース video_start # => [[0, 0]] > video_update

    # => [[0, 20]] video_stop # => [[0, 20]] video_start # => [[0, 20], [30, 30]] # seek forward video_update # => [[0, 20], [30, 50]] video_update # => [[0, 20], [30, 60]] video_stop 16
  7. #sapurimeetup 動画の視聴ログの実装について 理想的なケース video_start # => [[0, 0]] video_update #

    => [[0, 20]] > video_stop # => [[0, 20]] video_start # => [[0, 20], [30, 30]] # seek forward video_update # => [[0, 20], [30, 50]] video_update # => [[0, 20], [30, 60]] video_stop 17
  8. #sapurimeetup 動画の視聴ログの実装について 理想的なケース video_start # => [[0, 0]] video_update #

    => [[0, 20]] video_stop # => [[0, 20]] > video_start # => [[0, 20], [30, 30]] # seek forward video_update # => [[0, 20], [30, 50]] video_update # => [[0, 20], [30, 60]] video_stop 18
  9. #sapurimeetup 動画の視聴ログの実装について 理想的なケース video_start # => [[0, 0]] video_update #

    => [[0, 20]] video_stop # => [[0, 20]] video_start # => [[0, 20], [30, 30]] # seek forward > video_update # => [[0, 20], [30, 50]] video_update # => [[0, 20], [30, 60]] video_stop 19
  10. #sapurimeetup 動画の視聴ログの実装について 理想的なケース video_start # => [[0, 0]] video_update #

    => [[0, 20]] video_stop # => [[0, 20]] video_start # => [[0, 20], [30, 30]] # seek forward video_update # => [[0, 20], [30, 50]] > video_update # => [[0, 20], [30, 60]] video_stop 20
  11. #sapurimeetup 動画の視聴ログの実装について 理想的なケース video_start # => [[0, 0]] video_update #

    => [[0, 20]] video_stop # => [[0, 20]] video_start # => [[0, 20], [30, 30]] # seek forward video_update # => [[0, 20], [30, 50]] video_update # => [[0, 20], [30, 60]] > video_stop 21
  12. #sapurimeetup 動画の視聴ログの実装について (Welcome to) Real World video_start # => [[0,

    0]] > video_start # => [[0, 0], [30, 30]] # seek forward # video_update # => [[0, 20]] # video_stop # => [[0, 20]] 23
  13. #sapurimeetup 動画の視聴ログの実装について (Welcome to) Real World video_start # => [[0,

    0]] video_start # => [[0, 0], [30, 30]] # seek forward # video_update # => [[0, 20]] # video_stop # => [[0, 20]] > video_update # => [[0, 0], [30, 50]] video_update # => [[0, 0], [30, 60]] video_stop 24
  14. #sapurimeetup 動画の視聴ログの実装について (Welcome to) Real World video_start # => [[0,

    0]] video_start # => [[0, 0], [30, 30]] # seek forward # video_update # => [[0, 20]] # video_stop # => [[0, 20]] video_update # => [[0, 0], [30, 50]] > video_update # => [[0, 0], [30, 60]] video_stop 25
  15. #sapurimeetup 動画の視聴ログの実装について (Welcome to) Real World video_start # => [[0,

    0]] video_start # => [[0, 0], [30, 30]] # seek forward # video_update # => [[0, 20]] # video_stop # => [[0, 20]] video_update # => [[0, 0], [30, 50]] video_update # => [[0, 0], [30, 60]] > video_stop 26
  16. #sapurimeetup 動画の視聴ログの実装について データ構造を以下のようにする ➔ 冪等にする ◆ 最後のデータを更新する、等のロジックを廃止し、基本的に array に追 加していくだけにする

    ➔ Stateless にする ◆ イベントをデータが持つことを廃止した。video_start, video_update, video_stop などをやめ video_attempt に統一。 27
  17. #sapurimeetup 動画の視聴ログの実装について After: 1. あるユーザが動画を見始める: [[0, 0, 0]] 2. そのまま視聴し続けた

    a. 20秒毎に position を送信し [[0, 0, 20], [0, 20, 40], [0, 40, 60]] となる 3. そして 121秒経った時に stop を押した: [[0, 0, 20], [0, 20, 40], [0, 40, 60], …, [0, 120, 121]] 4. 数秒先に seek して視聴を再開した: [[0, 0, 20], …, [0, 120, 121], [130, 130, 130]] 29
  18. #sapurimeetup 動画の視聴ログの実装について サーバにデータが届かなかった場合 ➔ 通常の場合問題はないが、例えば一時的にサーバが落ちている場合クライ アントのデータがロストしてしまうと、生徒の視聴履歴も消えてしまうことにな る。 ➔ また特に Native

    アプリではオフラインの状態になることも多く、アプリ自体も オフラインでの対応しているため、最初からサーバにデータを送信できないこ とは考慮にいれる必要がある。 32
  19. #sapurimeetup 動画の視聴ログの実装について 届くまでデータを送るようにする ➔ そのためまず視聴履歴等のデータは、Web の場合であれば localforage と いうライブラリを使って IndexedDB

    か localstorage にデータを enqueue します。 ➔ 適切な回数 retry を行い、もし規定の回数を超えて失敗した場合は一旦は 何もしません。また違う画面に行った場合は reload などのタイミングで retry を行います。 ➔ Android では当初から細かいロジックは異なりますが、基本的にはこれと同 じでデータをなるべく失わないための実装をしていた。 33