-
Notifications
You must be signed in to change notification settings - Fork 198
Remove Session.Touch() — TTL refresh belongs in the storage layer #4320
Description
Background
Session.Touch() updates an in-memory updated timestamp on every Manager.Get() call (manager.go:214). This timestamp is used by LocalStorage.DeleteExpired() to determine which sessions have gone stale.
For Redis-backed sessions, Touch() is dead weight — RedisStorage.Load already uses GETEX to atomically refresh the key TTL during the read. The in-memory timestamp update on the deserialized object is never persisted back to Redis, so it has no effect.
PR #4294 ("Drop RoutingStorage and Touch") removed the Storage-level Touch method for exactly this reason — it leaked a Redis-specific TTL concern onto a shared interface. The same reasoning applies to the Session-level Touch: TTL refresh is a storage concern, not a session-object concern.
What exists today
Sessioninterface declaresTouch()(manager.go)ProxySession.Touch()updatess.updated = time.Now()under a mutex (proxy_session.go:81)Manager.Get()callssess.Touch()on every lookup (manager.go:214)LocalStorage.DeleteExpired()checkssession.UpdatedAt()against a cutoff time- All mock session setups in tests must include
.EXPECT().Touch().AnyTimes()
What needs to happen
- Move the timestamp update into
LocalStorage.Load— whenLocalStoragereturns a session, it should update the session's timestamp itself (or track last-access time internally), rather than relying on the caller to callTouch(). - Remove
Touch()from theSessioninterface — this is a breaking interface change, so all implementations and mocks need updating. - Remove the
sess.Touch()call fromManager.Get()— each storage backend handles TTL/freshness internally (GETEXfor Redis, timestamp update for local). - Clean up mock expectations — remove all
.EXPECT().Touch().AnyTimes()lines from test files. - Verify
LocalStorage.DeleteExpiredstill works — ensure the local backend's cleanup still correctly identifies stale sessions after the refactor.
Open questions
What happens to UpdatedAt? If Touch() is removed from the Session interface, nothing updates the updated field on the session object. UpdatedAt() is part of the Session interface and may have callers that expect it to reflect last-access time. Options:
- Have
LocalStorage.LoadcallTouch()internally (keeps the field accurate for local, still meaningless for Redis) - Remove
UpdatedAt()from theSessioninterface entirely and let each storage backend track last-access time opaquely - Keep
UpdatedAtbut accept it only reflects creation/store time, not last access
Should CreatedAt/UpdatedAt live on the session object at all? These timestamps are lifecycle metadata used for expiry decisions — arguably a storage concern, not a property of the session's domain data. Redis tracks TTL natively and never consults these fields. LocalStorage could track last-access time in a wrapper struct (e.g., map[string]{ session Session; lastAccess time.Time }) instead of requiring every Session implementation to carry timestamp fields. This would shrink the Session interface and remove the need for Touch, CreatedAt, and UpdatedAt from session implementations and mocks.
Why this matters
- Removes a leaky abstraction — storage backends should own their TTL semantics
- Eliminates a no-op code path for Redis-backed sessions
- Reduces mock boilerplate across all session-related tests
- Aligns with the direction established in Drop RoutingStorage and Touch: GETEX already handles TTL refresh #4294