1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-09 00:18:26 +01:00

feat: max parallel sessions config (#9109)

This commit is contained in:
Mateusz Kwasniewski 2025-01-20 11:51:50 +01:00 committed by GitHub
parent bbbc85245c
commit e9db8ab8f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 43 additions and 50 deletions

View File

@ -149,6 +149,7 @@ exports[`should create default config 1`] = `
"clearSiteDataOnLogout": true,
"cookieName": "unleash-session",
"db": true,
"maxParallelSessions": 5,
"ttlHours": 48,
},
"strategySegmentsLimit": 5,

View File

@ -266,7 +266,7 @@ const defaultDbOptions: WithOptional<IDBOption, 'user' | 'password' | 'host'> =
applicationName: process.env.DATABASE_APPLICATION_NAME || 'unleash',
};
const defaultSessionOption: ISessionOption = {
const defaultSessionOption = (isEnterprise: boolean): ISessionOption => ({
ttlHours: parseEnvVarNumber(process.env.SESSION_TTL_HOURS, 48),
clearSiteDataOnLogout: parseEnvVarBoolean(
process.env.SESSION_CLEAR_SITE_DATA_ON_LOGOUT,
@ -274,7 +274,16 @@ const defaultSessionOption: ISessionOption = {
),
cookieName: 'unleash-session',
db: true,
};
// default limit of 100 for enterprise, 5 for pro and oss
// at least 1 session should be allowed
maxParallelSessions: Math.max(
parseEnvVarNumber(
process.env.MAX_PARALLEL_SESSIONS,
isEnterprise ? 100 : 5,
),
1,
),
});
const defaultServerOption: IServerOption = {
pipe: undefined,
@ -533,11 +542,6 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
options.db || {},
]);
const session: ISessionOption = mergeAll([
defaultSessionOption,
options.session || {},
]);
const logLevel =
options.logLevel || LogLevel[process.env.LOG_LEVEL ?? LogLevel.error];
const getLogger = options.getLogger || getDefaultLogProvider(logLevel);
@ -638,6 +642,12 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
ui.environment,
isTest,
);
const session: ISessionOption = mergeAll([
defaultSessionOption(isEnterprise),
options.session || {},
]);
const metricsRateLimiting = loadMetricsRateLimitingConfig(options);
const rateLimiting = loadRateLimitingConfig(options);

View File

@ -98,6 +98,8 @@ class UserService {
readonly unleashUrl: string;
readonly maxParallelSessions: number;
constructor(
stores: Pick<IUnleashStores, 'userStore'>,
{
@ -106,6 +108,7 @@ class UserService {
authentication,
eventBus,
flagResolver,
session,
}: Pick<
IUnleashConfig,
| 'getLogger'
@ -113,6 +116,7 @@ class UserService {
| 'server'
| 'eventBus'
| 'flagResolver'
| 'session'
>,
services: {
accessService: AccessService;
@ -133,6 +137,7 @@ class UserService {
this.sessionService = services.sessionService;
this.settingService = services.settingService;
this.flagResolver = flagResolver;
this.maxParallelSessions = session.maxParallelSessions;
process.nextTick(() => this.initAdminUser(authentication));
@ -431,22 +436,14 @@ class UserService {
);
}
const deleteStaleUserSessions = this.flagResolver.getVariant(
'deleteStaleUserSessions',
);
if (deleteStaleUserSessions.feature_enabled) {
const allowedSessions = Number(
deleteStaleUserSessions.payload?.value || 5,
// subtract current user session that will be created
const deletedSessionsCount =
await this.sessionService.deleteStaleSessionsForUser(
user.id,
Math.max(this.maxParallelSessions - 1, 0),
);
// subtract current user session that will be created
const deletedSessionsCount =
await this.sessionService.deleteStaleSessionsForUser(
user.id,
Math.max(allowedSessions - 1, 0),
);
user.deletedSessions = deletedSessionsCount;
user.activeSessions = allowedSessions;
}
user.deletedSessions = deletedSessionsCount;
user.activeSessions = this.maxParallelSessions;
this.eventBus.emit(USER_LOGIN, { loginOrder });
return user;

View File

@ -54,7 +54,6 @@ export type IFlagKey =
| 'enterprise-payg'
| 'flagOverviewRedesign'
| 'showUserDeviceCount'
| 'deleteStaleUserSessions'
| 'memorizeStats'
| 'granularAdminPermissions'
| 'streaming'

View File

@ -45,6 +45,7 @@ export interface ISessionOption {
db: boolean;
clearSiteDataOnLogout: boolean;
cookieName: string;
maxParallelSessions: number;
}
export interface IVersionOption {

View File

@ -18,7 +18,6 @@ import PasswordMismatch from '../../../lib/error/password-mismatch';
import type { EventService } from '../../../lib/services';
import {
CREATE_ADDON,
type IFlagResolver,
type IUnleashStores,
type IUserStore,
SYSTEM_USER_AUDIT,
@ -51,7 +50,9 @@ const allowedSessions = 2;
beforeAll(async () => {
db = await dbInit('user_service_serial', getLogger);
stores = db.stores;
const config = createTestConfig();
const config = createTestConfig({
session: { maxParallelSessions: allowedSessions },
});
eventBus = config.eventBus;
eventService = createEventsService(db.rawDatabase, config);
const groupService = new GroupService(stores, config, eventService);
@ -66,31 +67,14 @@ beforeAll(async () => {
sessionService = new SessionService(stores, config);
settingService = new SettingService(stores, config, eventService);
const flagResolver = {
isEnabled() {
return true;
},
getVariant() {
return {
feature_enabled: true,
payload: {
value: String(allowedSessions),
},
};
},
} as unknown as IFlagResolver;
userService = new UserService(
stores,
{ ...config, flagResolver },
{
accessService,
resetTokenService,
emailService,
eventService,
sessionService,
settingService,
},
);
userService = new UserService(stores, config, {
accessService,
resetTokenService,
emailService,
eventService,
sessionService,
settingService,
});
userStore = stores.userStore;
const rootRoles = await accessService.getRootRoles();
adminRole = rootRoles.find((r) => r.name === RoleName.ADMIN)!;

View File

@ -201,6 +201,7 @@ unleash.start(unleashOptions);
instructing the browser to clear all cookies on the same domain Unleash is running on. If disabled unleash will
only destroy and clear the session cookie. Defaults to _true_. `SESSION_CLEAR_SITE_DATA_ON_LOGOUT`
- _cookieName_ - Name of the cookies used to hold the session id. Defaults to 'unleash-session'.
- _maxParallelSessions_ - The maximum number of parallel user sessions with password based login. `MAX_PARALLEL_SESSIONS`
- **ui** (object) - Set of UI specific overrides. You may set the following keys: `environment`, `slogan`.
- **versionCheck** - the object deciding where to check for latest version
- `url` - The url to check version (Defaults to `https://version.unleash.run`) - Overridable