Fix alt-create zombie login (never 'login already in flight' again)
HandleAltCreate submitted the login via SessionMgr().LoginBot immediately after BotCharacterFactory::Create. SaveToDB is async, so the character row is not committed yet: BeginLogin's holder loads nothing, the BotSession never completes and never leaves sessions_ — the bot appears 'stuck in login' and every later .playerbot login fails with 'login already in flight'. The .playerbot squad path already avoided this; alt create now matches it by deferring to DrainAltFinalizes, which submits the login on the next world tick against the committed row + CharacterCache entry. Also hardened DrainAltFinalizes: an in-flight session older than 25s is a wedged zombie — reap it (LogoutBot) and resubmit once so a leftover zombie from a pre-fix build (or any future race) self-heals instead of wedging that bot forever.
This commit is contained in:
@@ -3441,6 +3441,13 @@ void Module::DrainAltFinalizes(uint32 /*now_ms*/)
|
||||
|
||||
constexpr uint32 kMaxWaitMs = 120000; // 2 minutes
|
||||
constexpr uint8 kMaxAttempts = 240; // ~250ms tick → ~60s+; hard cap
|
||||
// A login that is still in flight this long after the queue entry was
|
||||
// created is a zombie: BeginLogin was submitted against an uncommitted
|
||||
// character row (or a wedged holder), so the BotSession never completes
|
||||
// and never leaves sessions_ — every later `.playerbot login` then fails
|
||||
// with "login already in flight". Reap it and resubmit on the now
|
||||
// committed row. Normal logins land in well under this window.
|
||||
constexpr uint32 kZombieReapMs = 25000;
|
||||
|
||||
std::vector<PendingAltFinalize> still;
|
||||
still.reserve(pending_alt_finalize_.size());
|
||||
@@ -3488,7 +3495,31 @@ void Module::DrainAltFinalizes(uint32 /*now_ms*/)
|
||||
|
||||
if (inFlight)
|
||||
{
|
||||
// Login already submitted — do NOT call LoginBot again
|
||||
// Login already submitted — do NOT call LoginBot again. But a
|
||||
// login can wedge permanently (see kZombieReapMs): if BeginLogin
|
||||
// ran against an uncommitted character row the holder loads
|
||||
// nothing, the session never completes, and the bot stays
|
||||
// "login already in flight" forever. Reap it once the sanity
|
||||
// window elapses and resubmit against the committed row.
|
||||
if (getMSTimeDiff(e.queued_ms, now) >= kZombieReapMs)
|
||||
{
|
||||
::Playerbot::Services::SessionMgr().LogoutBot(e.botGuid);
|
||||
TC_LOG_ERROR("playerbot.v2",
|
||||
"[AltFinalize] reaped zombie login bot={} elapsed_ms={}",
|
||||
e.botGuid.ToString(), getMSTimeDiff(e.queued_ms, now));
|
||||
|
||||
auto lr = ::Playerbot::Services::SessionMgr().LoginBot(e.botGuid);
|
||||
TC_LOG_ERROR("playerbot.v2",
|
||||
"[AltFinalize] LoginBot retry bot={} ok={} reason={}",
|
||||
e.botGuid.ToString(), lr.ok, lr.reason);
|
||||
|
||||
if (lr.ok)
|
||||
{
|
||||
requeue("login_submitted");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
requeue("login_in_flight");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -7846,15 +7846,16 @@ index 0000000000..8119d9c01a
|
||||
+ "[alt create] OK name={} guid={} race={} class={}",
|
||||
+ picked.name, id, uint32(picked.race), uint32(picked.cls));
|
||||
+
|
||||
+ auto login = SessionMgr().LoginBot(r.guid);
|
||||
+ if (!login.ok)
|
||||
+ handler->PSendSysMessage("Altbot %s created; login deferred (%s).",
|
||||
+ picked.name.c_str(), login.reason.c_str());
|
||||
+ else
|
||||
+ handler->PSendSysMessage("Altbot %s created (login submitted).",
|
||||
+ picked.name.c_str());
|
||||
+
|
||||
+ // Do NOT submit the login here. The character row is not DB-committed yet
|
||||
+ // (SaveToDB is async), so BeginLogin loads nothing and the BotSession
|
||||
+ // would sit in sessions_ forever as an "in flight" zombie that never
|
||||
+ // enters world — every later `.playerbot login` then reports
|
||||
+ // "login already in flight". DrainAltFinalizes submits the login on the
|
||||
+ // next world tick, by which time the row is committed and the
|
||||
+ // CharacterCache entry exists. (Mirrors the .playerbot squad path.)
|
||||
+ Module::instance().QueueAltFinalize(r.guid, me->GetGUID(), me->GetLevel());
|
||||
+ handler->PSendSysMessage("Altbot %s created; will log in momentarily.",
|
||||
+ picked.name.c_str());
|
||||
+ return true; // success — no help text
|
||||
+ }
|
||||
+
|
||||
|
||||
@@ -7600,15 +7600,16 @@ index 0000000000..8119d9c01a
|
||||
+ "[alt create] OK name={} guid={} race={} class={}",
|
||||
+ picked.name, id, uint32(picked.race), uint32(picked.cls));
|
||||
+
|
||||
+ auto login = SessionMgr().LoginBot(r.guid);
|
||||
+ if (!login.ok)
|
||||
+ handler->PSendSysMessage("Altbot %s created; login deferred (%s).",
|
||||
+ picked.name.c_str(), login.reason.c_str());
|
||||
+ else
|
||||
+ handler->PSendSysMessage("Altbot %s created (login submitted).",
|
||||
+ picked.name.c_str());
|
||||
+
|
||||
+ // Do NOT submit the login here. The character row is not DB-committed yet
|
||||
+ // (SaveToDB is async), so BeginLogin loads nothing and the BotSession
|
||||
+ // would sit in sessions_ forever as an "in flight" zombie that never
|
||||
+ // enters world — every later `.playerbot login` then reports
|
||||
+ // "login already in flight". DrainAltFinalizes submits the login on the
|
||||
+ // next world tick, by which time the row is committed and the
|
||||
+ // CharacterCache entry exists. (Mirrors the .playerbot squad path.)
|
||||
+ Module::instance().QueueAltFinalize(r.guid, me->GetGUID(), me->GetLevel());
|
||||
+ handler->PSendSysMessage("Altbot %s created; will log in momentarily.",
|
||||
+ picked.name.c_str());
|
||||
+ return true; // success — no help text
|
||||
+ }
|
||||
+
|
||||
|
||||
Reference in New Issue
Block a user