ググってもなかなか出てこない情報なので、どこかの誰かの役に立つかもしれないと思い、メモとして残しておく。必要になる場面はよくわからない。
if os.name == "nt": asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) while True: time.sleep(60) now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))).replace(second=0, microsecond=0) if now.minute != 0: continue bot = commands.Bot(command_prefix=(" "), intents=intents, help_command=None, loop=asyncio.new_event_loop()) @bot.event async def on_ready(): shori() await bot.close() bot.run(TOKEN)
importとかはわかると思うので略。
注意点
Windows環境でloopを閉じる際に問題があるらしく、event_loop_policyを変更しないとbot.close()で「RuntimeError: Event loop is closed」エラーが出て止まってしまう。Linuxなら必要ないはずだが、結局本番環境では動かさなかったので未検証。
これは指定の処理を実行したらBotを終了させてループ待機に戻り、分が0、つまり1時間毎に動作するようにしている。しばらくBotを動かし続けたい場合は、簡易的にやるならon_readyにasyncio.sleep()を入れるか、tasks.loopで1分周期確認してbot.close()するなりしよう。もちろんその際はtime.sleep()を消すように。
経緯と顛末
そもそもなんで書いたかというと、Botの導入数統計を得たかったから。しかしメンバーインテントは取得していないので、Bot起動時にだけ流れてくるGuild.member_countのデータの合計を記録することにした。
Dpy2.0stableであれば、わざわざBotを再起動せずともBot.fetch_guildでGuild.approximate_member_countを更新して取得できるのだが、私が使っている2.0a3575(更新停止宣言したときのやつ)では未実装なため、再起動が必要だった。もちろんそのうちstableにはするが、移行ガイド読むのがめんどくさかったのでとりあえず2.0aのままでやりたい。
で、1時間毎の再起動をしてmember_countの更新には成功し、DBにも書き込まれだしたのだが、5時間ほどで「member_count属性が存在しない」旨のエラーが出て止まってしまった。半日空けて15分間隔にすると1時間強で同様のエラーが出た。
どうやら短時間に5回程度再起動するとDiscord側から規制がかかり、member_countの値を渡してくれなくなるようだ。1時間に1000回接続するとTokenリセットで強制切断されるのは知っていたが、1時間に1回であっても部分的な規制対象になるのは意外だった。参考までにBotの所属ギルド数は1000である。テスト用の2サバBotでは10連続起動しても規制がかからなかったので、単純に回数で決まっているわけでもないようだ。あるいはコードを稼働させる前のテスト時点で10回前後やった再起動もカウントされているのか。
ともかく、再起動によってmember_countを得る試みは現実的でない。直接リクエストを投げてapproximate_member_countを取得することにした。
member_num = 0 for g in bot.guilds: member_num += (await bot.http.request(discord.http.Route('GET', '/guilds/{guild_id}', guild_id=g.id), params={"with_counts": "true"}))["approximate_member_count"]
これを1時間周期で稼働させているが、24時間経過しても規制がかかった気配はない。
……と思いきや1ヶ月後に403が返ってくるようになった。やりすぎたかもしれない。1時間毎のデータはあまり必要ないことがわかったので、しばらく休ませてから半日毎で再度試すつもり。
コメント