Skip to content

Characters stay online after the player logs out and closes the client ("zombie sessions") #51

Description

@meketreve

Status: TODO — Priority: MEDIUM — Area: Networking / Sessions

Reported by the lead developer on Discord, 2026-08-15. Filed here so it has a thread; the matching backlog entry is ISSUE-041 in docs/backlog/issues.md.

Problem

Players are sometimes shown as online after they have logged out and closed the game client. Reported from live server experience; previous attempts were made to address it and none is confirmed to have fixed it. Not reproduced in a development environment.

A mechanism that produces exactly this symptom is already documented inside ISSUE-038 (the memory-growth investigation), which found it while looking for something else:

  • TcpConnection (src/Perpetuum/Network/TcpConnection.cs:32) sets the OS-level TCP keepalive, and that keepalive is the only backstop for a peer that disappears without a clean TCP close.
  • There is no application-level heartbeat or idle timeout. ZoneSession tracks _lastReceivedPacketTime / InactiveTime, but it is read in exactly one place — Player.cs:1305, for the "was this player AFK at time of death" loot calculation — and never compared against a threshold to force a disconnect.
  • Until the keepalive fires, SessionManager keeps the entry, Character.IsOnline stays true, and the ghost's Player stays InZone and is still processed by the zone tick every frame.

ISSUE-038 shipped a mitigation for that path — keepalive time reduced from 24 hours to 2 hours, confirmed live in TcpConnection.cs:32 — and explicitly deferred the robust fix, recording an application-level idle timeout as "Deliberately not done ... user was offered this as an option and did not request it. Worth reconsidering if 2h keepalive still isn't tight enough after real-world observation." That observation has now been reported, so the deferral is due for review.

One detail does not fit and should be settled first. The keepalive mechanism above explains ungraceful disconnects — a crash, a force-kill, a dropped network, a closed laptop lid. The report describes a graceful exit: the player logged out and closed the client, which should send a clean TCP close and run the normal session teardown. Either the reports also cover ungraceful cases, or the logout path itself sometimes fails to tear the session down. Those are different defects with different fixes, and the evidence to tell them apart has not been gathered.

Impact

  • Players appear online when they are not. This is visible to everyone and misinforms corporation coordination and PvP decisions.
  • Every surviving ghost holds its Player in the zone and keeps it inside the ProcessManager tick loop, so it costs CPU as well as memory for as long as it lives. This is the mechanism ISSUE-038 identified as a likely contributor to the reported memory growth.
  • Anything gated on online state acts on stale information for the lifetime of the ghost.

Proposed fix

  1. Establish which case is actually being reported — graceful logout or ungraceful disconnect — before changing anything. A session that survives a clean logout is a different defect from one that survives a dropped connection.
  2. If graceful logouts are affected, audit the session teardown path end to end: the client's logout command, SessionManager removal, Character.IsOnline, and the removal of the Player from the zone. A teardown that is skipped or that fails partway would leave exactly this state.
  3. If only ungraceful disconnects are affected, implement the application-level idle timeout that ISSUE-038 deferred, using the InactiveTime that ZoneSession already tracks. This does not depend on OS keepalive behaviour, which NATs and firewalls can interfere with.
  4. Cover the teardown at the unit tier with a fake session, and the surviving-state question at the integration tier.

Notes

  • Priority is a judgement made when filing; the report did not assign one. MEDIUM rather than higher because a partial mitigation already shipped. Raise it if the graceful-logout path turns out to be the cause, since that would mean an ordinary logout can leave a ghost.
  • Filed separately from ISSUE-038 rather than folded into it: that issue is about memory growth and would close on a memory measurement, while the visible-online symptom is what players actually report and needs to survive that issue closing.
  • Every line number above was checked against 4e6d697 and is anchored to it. Line numbers drift.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions