Open KisaragiEffective opened 2 months ago
ちぎる
ちぎる
スレッドチェーンが 100 超えると DoS 判定でアクティビティの受け取りをやめる処理がリトライされるのがそもそも悪そうで リトライ時に一番上まで遡れたところからリトライしてほしさある
例: Note1→Note2→Note3→Note4→Note5→Note6→Note7→Note8→Note9→Note10 ※ →はリプライの方向 (左が右の投稿にリプライしている)
現状: Note1が来た際にreplyToをNote10まで再帰解決を試みるが、最後まで解決出来ないとNote1~10すべてがエラーになってしまう。 この場合毎回Note1から再試行してしまう。
単純にちぎる案?: 例えばNote7までしか解決出来なかったらそこでNote1~7を確定してコミットしてしまう? Note1→Note2→Note3→Note4→Note5→Note6→Note7 現状のNoteのDBスキーマ的にはリプライしている or not しかないため、この場合Note7はどこにもリプライしてない状態が受信サーバーでは確定してしまい、追加解決出来る余地もなくリプライが続いていることをユーザーは認知も出来ない。
リトライ時に一番上まで遡れたところからリトライしてほしさある: 実現するには… DBスキーマのNoteのリプライ状態に、あり/なし以外に"このAP IDにリプライをしているが未解決"のステータスを持たせたる必要がある? また、リプライ解決をNote取得のフォアグラウンドプロセスで行うだけではなく、ジョブキューでのバックグラウンド解決を検討するとベター?
って感じかしら
ApNoteService.resolveNote~createNoteの引数でcreateNoteの回数をカウントアップして、100を超えたらそこでエラーにして再実行を促すなりキューを(正当な手続きで)登録し直すみたいな感じはどうかしら
↑hit recursion limitの仕組み自体追ってなかったけどresolver.resolveの回数を見てるのか
ApNoteService.resolveNote~createNoteの引数でcreateNoteの回数をカウントアップして、100を超えたらそこでエラーにして再実行を促すなりキューを(正当な手続きで)登録し直すみたいな感じはどうかしら
それが理想だけど
現状のDBスキーマ的にリプライ先は取得済みでないと存在できないから(つまり再帰エラーはもうリプライが存在しないというステータスにしかできない)
Note.replyId: MiNote['id']
onDelete: 'CASCADE'
それを実現するには、DBスキーマに未解決のAP IDカラムを新設して追加解決を実装する必要があるという感じだわね。
あっ
キュー自体に処理中のデータを持たせるみたいなこと考えたけどRedisが肥大化するしなぁ
replyId/replyをnullにして後で上書きするのが構わなさそうなら、リプライツリーを遡る専用のジョブキューを用意してそういう処理をさせるとか?
ところで、「Inboxが詰まる」事象は100件という数字が大きすぎるという話なのでまだおとなしい数字にする必要がある
どこまで頑張るかだわね。
ちなみにリプライ解決が詰まるパターンって、100到達だけではなく途中のリプライを所有するサーバーが500等の一時的エラーを返すパターンもある気がするのだわ。
そもそもどうして詰まるというかハングするのかは考えないのかしら
(別にこの問題に限らないけど十分丁寧な実装にしたあとのバージョンで何度繰り返しても死ぬものをキューに詰め直すのをやめたい感じ)
現状だとリトライする価値のあるエラーとリトライする価値のないエラーが混在してるので運が悪い(?)と詰まる
ちなみにリプライ解決が詰まるパターンって、100到達だけではなく途中のリプライを所有するサーバーが500等の一時的エラーを返すパターンもある気がするのだわ。
また、リプライ解決の途中で4xx等の恒久的エラーを返された場合は、現状のMisskeyのスキーマ的に存在しないNoteのリプライは存在出来ないので、リプライツリーすべてを存在しないことにして完了してリトライもしない。にするべきだけどちゃんとその仕様で実装されてるかは自信ないのだわ。
再帰制限100突破でリトライしてしまう → リトライしてはいけない (とりあえずちぎるかもっと頑張るか?) 解決途中で5xx (一時エラー) →とりあえずリトライするしかないか 解決途中で4xx (恒久エラー) →リトライしてはいけない、リプライツリーはすべて存在しないものとして扱わないといけない
みたいな…
「リプライチェーンが長すぎるせいで」は関係なくなってきた気がするしissueのタイトル変える?
確かに、リプライ/引用の解決時エラーの実装ってもやっとしてるわね。
とりあえず変えてみた
リプライツリーの全て(というよりDoS攻撃にはならない範囲)のノートを一回new MiNote
で作っておいて1回のdb transactionで流し込むようにすれば多少ハングはましになるし
リプライツリーすべてを存在しないことに
という処理も可能になりそうだけど、そういう処理(同一トランザクションでidがcascade関係にある)が可能なのかはDB詳しくないのでわからない
あとPollも絡んできて処理は若干複雑になりそう
「リプライチェーンが長すぎるせいで」は関係なくなってきた気がする
うーん?リプライツリーのノートを大量取得する際にinboxが詰まるというか1つのinboxキューの処理に時間とリソースが食われてる状況だと思うので、「リプライチェーンが長すぎるせいで」は関係なくはないと思うんだけど
「リプライチェーンが長すぎるせいで」は関係なくはない
まぁはい もしかしてissue分けたほうがいい?
分けなくてもいいのでは
あー、色々ごちゃごちゃ言っちゃったけどちぎるって話か(あんまちぎらない前提でごちゃごちゃ喋ってしまった
あーそういえばキューの最大処理時間で問答無用で終了パターンもあるからめんどくさいわね。やっぱりここまで処理したフラグないとダメかしら。
頭の中ではApRenderService
あたりで何らかの一時中断 (100 recursion, 5xx, timeout) をせざるを得なくなったらジョブキューにサブツリーのrenderを詰め直すで良いんじゃないかなぁとか思ってた
実現できるかどうかは知らない
うーん、サーバーに必要以上にリプライを持ってても嬉しくないので、ここまで処理したフラグというか、「replyUri」みたいにリプライ先のuriを保存しておいて、UIのボタンでページングのごとく取得できるみたいな感じがサーバー的には嬉しいと思う
実装はやや面倒である
後でやるか先にやるかの違いでしか無いかも
あまりにたくさんあったら遅延評価されたほうが嬉しい?
遅延評価したらrenderが完了するまで照会のloadingがUIで回ることになって困惑しそう
まぁユースケース的に大きくなった線形リストみたいなリプライツリーを最後まで追う熱心なユーザーはほとんど居ないか……
まぁユースケース的に大きくなった線形リストみたいなリプライツリーを最後まで追う熱心なユーザーはほとんど居ないか……
そうこれを期待できる
そうでなくてもページングで全件取得してくる必要は全くない(10~20件とってきてまだあるようならまたユーザーにボタンを押させれば良い
UIのボタン
今のUIは「会話を見る」だったわね
あれのlimitって深さ方向じゃなくて水平方向だったような…?
あれのlimitって深さ方向じゃなくて水平方向だったような…?
NoteだろうがUserだろうがもしかしたら固定投稿だろうが区別せずに問答無用で100だったかもだわ
notes/conversationって深さ方向にしか追わなくない…?
notes/conversationって深さ方向にしか追わなくない…?
NoteだろうがUserだろうがもしかしたら固定投稿だろうが区別せずに問答無用で100だったかもだわ
AP側のhit recursion limitの100はresolver.resolveを見てるのでノート以外に追加で必要なデータがあったら+1カウントされるわね
今のUIは「会話を見る」だったわね
これ(notes/conversationを呼び出す処理)、NoteDetailedにしかないし10件取得したらそれで満足やろみたいな仕様になってるわね
若干オフトピ: 正直足りないことちょくちょくあるので見るベージはほしい
replyUriを保存した場合はNoteEntityService.pack (detail: true)の呼び出しによってreplyUriを解決するみたいな感じでいいのか?(inboxキュー処理内でリプライ先を解決する必要すらない?)
いやよくない、祖先が削除されていたらその子供はCASCADE削除されなければならない
オフトピ:
conversationの話ね
祖先が削除されていたらその子供はCASCADE削除されなければならない
(そもそもこの仕様自体顰蹙買ってるわけだけど: Related to https://github.com/misskey-dev/misskey/issues/7342
そしてこの仕様がある限り、データベースに追加したりストリーム配信する前に全ての親を遡って取得して削除されていないか確認する必要がある、ちぎってもいけない
そうなの?子孫をちぎるのは問題ないと思うのだけど
今子孫関係なくない?というかinboxでやってきたおnewのノートに子孫がいるわけない
そっか
💡 Summary
元々のお題: リプライツリーが長すぎるとinboxで詰まる reported on https://misskey.hinasense.jp/notes/9xsg30de8l4b001m
🥰 Expected Behavior
inboxで詰まらせずに:
チェーン全体の解決を諦めるか上限に達した時にそれ以上のチェーンは存在しないものとしてチェーンをちぎるどうであれinboxには詰まらないようにしたい
🤬 Actual Behavior
inboxで詰まる
📝 Steps to Reproduce
💻 Frontend Environment
🛰 Backend Environment (for server admin)
Do you want to address this bug yourself?