SessionBackend::save() can be triggered directly, e.g when persisting the session. It will also be called automatically whenever the last Session bound to that SessionBackend is destructed. Those are both somewhat problematic:
- They make session save behavior unpredictable. More so when being called from the destructor (which can cause issues like T400113: Circular dependency due to random Session object calling UserNameUtils service), but even being called directly from various Session methods is often unintuitive when one looks at the high-level flow, and leads to hacks like rMW3168669776d3: LoginSignupSpecialPage: Get a login token before persisting the session.
- They can result in multiple writes to the same session ID, which can exacerbate infrastructure problems ({T390514}).
It would be better to do these saves at some deterministic point in time, presumably somewhere around MediaWikiEntryPoint::commitMainTransaction() (as it needs to be soon enough to influence cookie headers, but late enough to include all session changes).