108 行
7.9 KiB
Markdown
108 行
7.9 KiB
Markdown
# Counts エクスポートワーカー
|
|
|
|
Counts の画面からのエクスポートは永続ファイルキューへ登録する。
|
|
Active Job の既定のプロセス内 async アダプターは使用しない。
|
|
追加 gem、外部キュー、DB マイグレーションは不要。
|
|
|
|
## 起動・配置
|
|
|
|
backend で `bundle exec rake counts:export_worker` を、systemd 等の監視対象として
|
|
別プロセスで起動する。Web プロセス内では起動しない。
|
|
1監視プロセスは同時に1ジョブを専用の子プロセスで生成し、全体の実行枠は
|
|
既存の2枠を共有する。fork 前に DB 接続を閉じ、子が独立した接続を取得する。
|
|
Web 内のスレッドや Active Job async では実行しない。Linux / POSIX の fork が必要。
|
|
監視側は SQL 中も1秒間隔でジョブとワーカーの heartbeat を更新する。
|
|
|
|
`docs/systemd/btrc-counts-exports.service` を配備用 unit として追加している。
|
|
Restart=always、KillMode=control-group、停止猶予150秒を指定している。
|
|
User、WorkingDirectory、bundle が見つかる PATH を実際の配備先へ合わせる。
|
|
`/etc/btrc-hub/counts-exports.env` に Web と同じ Rails secret・接続設定・
|
|
COUNTS_EXPORT_DIRECTORY を設定し、同じ Unix ユーザーで読み書きできるようにする。
|
|
OS 起動時の有効化・サービス起動は運用側で行う必要がある。
|
|
今回 unit のインストール、有効化、本番での起動・再起動は行っていない。
|
|
|
|
Web とワーカーは同一リリース、Rails secret、アプリケーション環境、DB 接続先を
|
|
使用する。DB コネクションはワーカープロセスごとに必要。
|
|
`COUNTS_EXPORT_DIRECTORY` を同じ永続 POSIX 共有ディレクトリに設定する。
|
|
省略時は `backend/tmp/counts_exports`。
|
|
全プロセスで同一の所有者とアクセス権を使用する。
|
|
複数ホストでは、flock・同一ファイルシステム内の atomic rename・fsync が正しく
|
|
機能する共有ボリュームが必須。オブジェクトストレージや各コンテナ独立の tmp は不可。
|
|
ジョブ JSON と完成ファイルが格納されるため、このディレクトリを静的公開しない。
|
|
|
|
## API と進捗
|
|
|
|
- POST `/counts/export/jobs`:要求検証・実行時点の固定・署名付きジョブトークンの発行。
|
|
- GET `/counts/export/jobs/:token`:状態、実際の処理済みレコード数、判明している総数。
|
|
- DELETE `/counts/export/jobs/:token`:取消を永続記録。
|
|
- GET `/counts/export/files/:token`:生成完了後の署名付きファイルトークンによる取得。
|
|
|
|
ジョブ・ファイルのトークンは作成元のセッションに紐付く。
|
|
既存の BAN・CSRF 制御を使用する。フロントは約800ms間隔で状態を取得する。
|
|
明細の総数は同じ読み取りトランザクション内の SQL 件数を使用する。
|
|
queued と running に加え、running 内の phase で aggregating(集計中)と
|
|
writing(出力中)を区別する。最初の SQL より前に aggregating を記録する。
|
|
heartbeat_at は監視側の生存時刻、updated_at は生成処理が状態を書いた時刻であり、
|
|
処理件数と分離する。SQL 中に件数は増やさない。
|
|
集計の総出力数は生成終了まで未確定とし、不確定進捗として扱う。
|
|
processed は CSV では実際に生成したデータ行数、JSON のクロス集計では
|
|
実際に生成した pivot_cell 数。ヘッダーは含めず、小計・合計の物理レコードは含む。
|
|
通常の集計行だけを数える logical_count_unit=regular_result_rows と区別する。
|
|
出力中は約250ms間隔と最終レコードで実測件数を保存する。
|
|
完成状態はファイルの生成完了であり、ブラウザの保存完了を意味しない。
|
|
|
|
## 取消・障害・制限
|
|
|
|
通常は約250ms間隔の生成チェックポイントで取消を検知する。
|
|
監視側も取消を確認し、子へ TERM、5秒後も終了していなければ KILL を送る。
|
|
子の回収後に一時ファイルを削除する。DB 側の実行停止は切断検知等に依存するため、
|
|
取消 API の受理と DB の即時停止は同義ではない。
|
|
取消済みへの遷移は生成処理の終了と一時ファイル削除後に行う。
|
|
既に始まった HTTP 転送やブラウザ側の保存は取り消せない。
|
|
|
|
ワーカーが異常終了したジョブは、次のワーカーが実行ロックを取得した際に失敗状態にし、
|
|
そのジョブの残存生成ファイルを削除する。別の読み取り状態で自動再実行しない。
|
|
原子的に書き換える状態ファイルとプロセス間ロックにより、二重処理・取消との競合を防ぐ。
|
|
|
|
既存の同時実行2、1ファイル128MiB、保存領域512MiB、生成120秒、期限10分を維持する。
|
|
生成120秒は監視側でも強制する。ワーカー未起動なら登録 API は503を返す。
|
|
待機中のワーカー消失、15秒以上の heartbeat 停止、150秒以上の待機は失敗とする。
|
|
ネットワーク切断時も UI が無期限に処理中にならないよう、状態取得は1回15秒で中断し、
|
|
30秒以上状態を取得できなければ失敗表示へ移る。処理件数を捏造しない。
|
|
画面からの通信断だけではサーバーの取消完了を保証しない。サーバー側の期限は独立して働く。
|
|
期限切れのジョブ・ファイル・残存状態書込ファイルは登録時またはワーカーの巡回時に削除する。
|
|
ワーカーと Web の両方を停止した間は巡回削除も停止する。
|
|
|
|
これらの処理は静的確認のみで、実環境のキュー処理・取消・転送・共有ボリュームでの
|
|
排他動作は未確認。
|
|
|
|
## Counts の件数と性能
|
|
|
|
通常の Counts 応答では、使用していない全履歴の population_count は計算しない。
|
|
キーは null、population_count_computed は false とし、0に置き換えない。
|
|
現在条件の output_count は権限適用前、visible_output_count は権限適用後の
|
|
通常の集計行数(明細では明細行数)。小計・合計の物理行は含めない。
|
|
CSV の物理行と JSON の pivot_cell には集計レコードを含むため、両者を混同しない。
|
|
|
|
除票境界・参照禁止集合は GROUP BY で識別キー単位にまとめる。
|
|
投稿の参照判定は、全除票履歴を JSON_CONTAINS / FIND_IN_SET で反復照合せず、
|
|
保存済みスナップショットから参照IDを JSON_TABLE で展開して照合する。
|
|
権限条件付きの母集団件数は同一 export インスタンス内で再利用する。
|
|
多段小計は、認可済み母集団の CTE を MySQL の無制限 LIMIT で実体化させ、
|
|
各枝が同じ認可判定をやり直すことを避ける。計数は COUNT(DISTINCT v.id) のまま。
|
|
|
|
スキーマ上、以下の追加インデックスが候補となる。migration は作成・実行していない。
|
|
|
|
- post_versions: (event_type, post_id, version_no)
|
|
- tag_versions / nico_tag_versions: (event_type, tag_id, version_no)
|
|
- tag_description_versions: (event_type, tag_id, language_code, version_no)
|
|
- tag_group_versions: (event_type, tag_group_id, version_no)
|
|
- material_versions: (event_type, material_id, version_no)
|
|
- 各履歴テーブル: (event_type, id)。ファイル認可の policy revision 用 MAX(id) の候補。
|
|
- post_versions 等で未整備の (created_at)。履歴の異動期間を絞る場合の候補。
|
|
- post_versions: (post_id, created_at, version_no)。日時指定の最新版探索の候補。
|
|
|
|
追加は許可後の新規 add_index migration として行い、既存 migration は変更しない。
|
|
実DBでのインデックス容量・作成時ロック・実行計画・時間は未確認。
|
|
索引追加なしでの最大データ量に対する応答時間は保証しない。
|