Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: auto-renew session expiry before expiry #206

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

harish2704
Copy link

Summary of the option ( copied from readme )

refresh (optional)

Automatically refresh ( extend the expiry of ) session before <refresh> milliseconds before expiry. This is more efficient way than setting rolling option.
The default value is 0 ms meaning, this feature is disabled.
Consider cookie.maxAge is 60 seconds. If we set refresh = 20 seconds, then it will auto refresh the session if sent any request after 40 second.
it is recommended to disable rolling and saveUninitialized options if we set this option

Checklist

Fixed dependency version.
Later versions of connect-redis exports a {default: ..} object
@@ -32,7 +32,7 @@
"@fastify/pre-commit": "^2.0.2",
"@types/node": "^20.1.0",
"connect-mongo": "^5.0.0",
"connect-redis": "^7.0.0",
"connect-redis": "7.0.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you lock the version?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I locked it because benchmark was not running due to following error

TypeError: redisStoreFactory is not a function

But, when I re-checked it now, I realized that I should have lock this version to ^6 rather than 7.0.0 because the error still happening in 7.0.0 version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The benchmark is fixed in #248 :)

@@ -93,6 +93,12 @@ Setting this to `false` can save storage space and comply with the EU cookie law
##### rolling (optional)
Forces the session identifier cookie to be set on every response. The expiration is reset to the original maxAge - effectively resetting the cookie lifetime. This is typically used in conjuction with short, non-session-length maxAge values to provide a quick expiration of the session data with reduced potential of session expiration occurring during ongoing server interactions. Defaults to true.

##### refresh (optional)
Automatically refresh ( extend the expiry of ) session before `<refresh>` milliseconds before `expiry`. This is more efficient way than setting `rolling` option.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it not clear what we should set - a boolean? a string?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refresh option is an number . it is a duration in milliseconds . I can fix this by editing the Readme once the discussion is complete.

Comment on lines 241 to 244
} else {
const shouldRefresh = refresh ? request.session.cookie.expires.getTime() < (Date.now() + refresh) : false
return rollingSessions || shouldRefresh || (Boolean(request.session.cookie.expires) && request.session.isModified())
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very unclear - consider refactoring it:

if rollingSessions is true, we are calculating the shouldRefresh var - and it is unnecessary.

Copy link
Author

@harish2704 harish2704 Aug 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very unclear - consider refactoring it:

The previous code was a big single ternary operator . I changed it to if else condition for the sake of readability .
I din't do anything else than calculating shouldRefresh

if rollingSessions is true, we are calculating the shouldRefresh var - and it is unnecessary.

Yes that is correct in terms of performance. I did this for the sake of code readability. I can fix this

@@ -187,6 +188,7 @@ function fastifySession (fastify, options, next) {
return
}

session.touch()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a bug like case while trying to implement this option.
The issue is this: the session.expiry was always dynamically calculated at the time of incoming request using maxage & Date.now() instead of loading it from session store.

This issue was not causing any problem since rolling option was enabled by default.
But if disable rolling option, session.expiry value will become a useless information because, it will be always unexpired value because it is calculated dynamically for each request.

But in overall, the system was working well due to proper session cleanup taking place in 1 second interval .

I fixed this behavior by loading expiry value from session store.

When that is done, we need to manually call touch() to extend the expiry of session before saving it into session store.

README.md Outdated Show resolved Hide resolved
@@ -13,6 +13,9 @@ module.exports = class Cookie {
this._expires = null

if (originalMaxAge) {
if (cookie.expires) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use originalMaxAge here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Please see my previous comment regarding expiry calculation bug. In this case, if cookie.expiry is set, it will be a string loaded from session store. So, it is converted to proper Date object using this if condition

@@ -40,7 +43,7 @@ module.exports = class Cookie {
}

set maxAge (ms) {
this.expires = new Date(Date.now() + ms)
if (!this.expires) { this.expires = new Date(Date.now() + ms) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not setting the maxAge any more here - why should we check it?

Copy link
Author

@harish2704 harish2704 Aug 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if conduction ensures that this.expiry is only set for newly created session and not for existing session loaded from session store .
For session loaded from session store, the expiry value will be already there ( it is determined at the time of session creation ).

Co-authored-by: Manuel Spigolon <[email protected]>
@harish2704
Copy link
Author

harish2704 commented Sep 10, 2023

@Eomm Let me know what you think about this PR. If you are ready to proceed , I will can make the changes you suggested .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants