Investigation
Generically speaking (on any node), the LogicalSessionCache on that node uses its ServiceLiaison's getActiveOpSessions() method to collect the set of currently active operations that are associated with a session.
(This is to collect the set of long-running operations that have been active since the last time the LogicalSessionCache updated the sessions records. New operations that have come in since the last time the LogicalSessionCache updated the sessions records are collected through LogicalSessionCache::vivify() in each node's service entry point).
The ServiceLiaison interface has a mongod and mongos implementation.
ServiceLiaison*Mongod*::getActiveOpSessions() walks through all Clients currently on the ServiceContext to collection the currently active operations.
However, the ServiceLiaison*Mongos*::getActiveOpSessions() simply looks at the open cursors currently in the CursorManager. As a result, even if there is no activity on these cursors, sessions with open cursors will not be reaped.
It looks like this is a copy-paste error, and that the lines in ServiceLiaisonMongos::getActiveOpSessions() should instead be here in ServiceLiaisonMongos::getOpenCursorSessions().
But, I think it's worth taking a step back to examine the ServiceLiaison on mongos and mongod to make sure it is capturing the right information - why doesn't the ServiceLiaisonMongos walk through Clients on its ServiceContext to capture long-running operations on sessions (the way ServiceLiaisonMongod does) that are not associated with a cursor and do not touch any shards?
This bug also affects 4.0.1 and 3.6.7.
Proposed Fix
We have agreed that the two service liaisons should behave in the same manner. We have also agreed that ServiceLiaison*Mongod has the correct implementation of both getActiveOpSessions() and getOpenCursorSessions().
- Move the implementation of ServiceLiaison*Mongos*::getActiveOpSessions() to ServiceLiaison*Mongos*::getOpenCursorSessions(), to match the ServiceLiaison*Mongod*getOpenCursorSessions() implementation.
- Mirror the implementation of ServiceLiaison*Mongod*::getActiveOpSessions() to match ServiceLiason*Mongod*::getActiveOpSessions().