運用
部屋のサーバー(Cloudflare版とVercel版)を置いたあと、運営する人が見ておくところと、裏で動いているしくみをまとめました。費用の目安は費用と上限に、預かるものと申し立てへの応えかたは運営の方針にあります。
見ておくところ
ADMIN_DISCORD_IDSを入れると、部屋の一覧と作った人、ログインや部屋を作った記録を、部屋のサーバーの/adminで見られます。思わぬ使われかたをする送信元やアカウントは、そこでBANできます(→ 管理画面とBAN)。
Cloudflare版
- Workersのダッシュボード:リクエスト数、エラーの割合、CPU時間。
observabilityを有効にしてあるので、ログもダッシュボードで見られます。 - R2のダッシュボード:バケットの大きさと、Class A・Class Bの操作数。
- Durable Objectsのダッシュボード:リクエスト数、動いていた時間(GB-s)、SQLiteの読み書きした行と大きさ。
- 部屋の記録:下の部屋の記録を見てください。
- 請求の通知:思わぬ使われかたに早く気づけるよう、Cloudflareの請求額の通知を設定しておくと安心です。
Vercel版
- プロジェクトのLogs:Functionのログ。無料のプランでは1時間しか残りません。
- プロジェクトのUsage:Functionの動いた時間とメモリ、Vercel Blobの量と読み書きの回数、転送量。
- Storageの中のRedis:コマンドの数と、置いている量。Redisの提供元(Upstashなど)の画面でも見られます。
部屋の記録
部屋のサーバーは、部屋で起きたこと(入った、出た、断った、書いた、振った、削除した)を記録します。だれのことかは記録しません。
| 出来事 | 中身 | 量 |
|---|---|---|
join | 役割 | 部屋にいる人数 |
leave | 役割 | つないでいた秒数 |
refuse | 接続を閉じた理由 | 1 |
flush | (空) | 1分のあいだに書いた数(Cloudflare版はSQLiteの行、Vercel版はRedisに書いたもの)。部屋が空になったときも書く |
roll | ゲームシステム | 振るのにかかったミリ秒 |
delete | gm(部屋のGMが削除した)かoperator(運営する人が管理画面から削除した) | 削除したときに部屋にいた人数 |
Cloudflare版
Workers Analytics Engineのデータセットudonarium_axe_roomsに書きます。データセットは最初に書いたときに作られるので、用意するものはありません。無料のプランでは1日10万点まで書けます。書いた行の数は1分ごとにまとめて1点にするので、4時間の卓で書くのは300点ほどです。
| 列 | 中身 |
|---|---|
index1 | 部屋の鍵 |
blob1 | Workerのホスト名 |
blob2 | 出来事(上の表) |
blob3 | 中身(上の表) |
double1 | 量(上の表) |
同じアカウントのWorkerは同じデータセットに書くので、blob1で分けて見ます。部屋を消しても、この記録は消えません。
flushの数は、書いたオブジェクトの数ではなく、SQLiteが書いた行の数です。部屋はオブジェクトを約8KiBずつ1行にまとめて置くので、ふつうは1回の書き込みで、変わったオブジェクトのある行ごとに1行です。大きなオブジェクトの行と、消した印の行も数えます。Durable Objectsの無料のプランの「SQLiteに書く行(1日10万)」と、そのまま比べられます。
SQL APIで読むには、Account Analytics Readの権限を付けたAPIトークンを使います。
curl "https://api.cloudflare.com/client/v4/accounts/<アカウントID>/analytics_engine/sql" \
-H "Authorization: Bearer <APIトークン>" \
--data "SELECT blob2 AS event, blob3 AS detail, count() AS n FROM udonarium_axe_rooms
WHERE blob1 = 'backend.example.com' AND timestamp > NOW() - INTERVAL '1' DAY
GROUP BY event, detail ORDER BY n DESC"Vercel版
Functionのログに、1つの出来事を1行のJSONで書きます。
{ "metric": "room", "room": "<部屋の鍵>", "host": "<ホスト名>", "event": "join", "detail": "pl", "value": 3 }プロジェクトのLogsで"metric":"room"を探すと、記録だけを見られます。無料のプランでは、ログは1時間しか残りません。
キャッシュ(Cloudflare版)
部屋のアセットのGETの答えにはCache-Control: private, max-age=604800, immutableを付けます。部屋が消えるまで中身は変わらないので、ブラウザには7日置かせます。ただし、トークンを持たない人に返らないよう、共有のキャッシュには置かせません。
Workerが作った答えは、CloudflareのCDNには自動では残りません。そこでCloudflare版は、GETの答えをCache APIに入れ、同じデータセンターからの2回目以降はそこから返します。キャッシュから返すときも、先に部屋のアセットのトークンを確かめます。同じ卓の参加者は同じデータセンターにつながりやすいので、R2を読むのは実質1人分で済みます。
*.workers.devではキャッシュが効きません
Cache APIは、*.workers.devのURLでは何もしません。本番では、Workerにカスタムドメインを付けてください(→ Cloudflareに置く)。
R2から消したあとも、データセンターのキャッシュには写しが最長7日残ります。ただし、キャッシュから返すときも先にトークンを確かめ、部屋が消えれば新しいトークンは出ないので、写しを読めるのは消してから最長15分です。部屋を残したまま、部屋のGMか運営する人が画像や音声を1つ消したときは、トークンが出続けるので、その部屋の席は写しを最長7日読めます。管理画面で二度と置かせないようにしたものは別です。各インスタンスは、BANと一緒にそのSHA-256を30秒ごとに読み直し、キャッシュから返す前に照らし合わせます。写しが残っていても、30秒ほどのうちに451 blockedを返すようになります。
Vercel版には、このキャッシュはありません。
消しそこねた画像と音声の掃除
部屋のアセットは、部屋と一緒に消します(→ 部屋が消えるとき)。置いてからの日数では消さないので、部屋が続いているあいだは消えません。
途中で落ちたときなどに消しそこねたものは、新しく置くついでに、少しずつ消します。
- 新しく置いた約20回に1回、置き場所の一部(Cloudflare版はランダムな位置から1000件、Vercel版は続きの1ページ)を見て、部屋の一覧に無い部屋のアセットを消します。
- 部屋を作るのと置くのが前後しても消さないよう、置いてから1時間たったものだけを消します。
- 置き場所はアップロードでしか増えないので、アップロードに合わせて掃除すれば、消しそこねたものがたまり続けることはありません。
- 置かせない印(
blocked/の下)は消しません。
R2のライフサイクル規則は要りません。作ると、続いている部屋のアセットも日数で消えてしまいます。
特定の画像を消したいとき
権利侵害の申し立てなどで特定の画像を消し、また置かせないようにする手順は、運営の方針にあります。