backend: Refactor MeetStorageService to initialize global preferences with locking mechanism
This commit is contained in:
parent
355d773dd1
commit
30ee4dfbca
@ -57,7 +57,7 @@ export const registerDependencies = () => {
|
|||||||
export const initializeEagerServices = async () => {
|
export const initializeEagerServices = async () => {
|
||||||
// Force the creation of services that need to be initialized at startup
|
// Force the creation of services that need to be initialized at startup
|
||||||
container.get(RecordingService);
|
container.get(RecordingService);
|
||||||
await container.get(MeetStorageService).buildAndSaveDefaultPreferences();
|
await container.get(MeetStorageService).initializeGlobalPreferences();
|
||||||
};
|
};
|
||||||
|
|
||||||
export { injectable, inject } from 'inversify';
|
export { injectable, inject } from 'inversify';
|
||||||
|
|||||||
@ -32,4 +32,8 @@ export class MeetLock {
|
|||||||
static getRoomGarbageCollectorLock(): string {
|
static getRoomGarbageCollectorLock(): string {
|
||||||
return `${RedisLockPrefix.BASE}${RedisLockName.ROOM_GARBAGE_COLLECTOR}`;
|
return `${RedisLockPrefix.BASE}${RedisLockName.ROOM_GARBAGE_COLLECTOR}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getGlobalPreferencesLock(): string {
|
||||||
|
return `${RedisLockPrefix.BASE}${RedisLockName.GLOBAL_PREFERENCES}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,5 +15,6 @@ export const enum RedisLockPrefix {
|
|||||||
export const enum RedisLockName {
|
export const enum RedisLockName {
|
||||||
ROOM_GARBAGE_COLLECTOR = 'room_garbage_collector',
|
ROOM_GARBAGE_COLLECTOR = 'room_garbage_collector',
|
||||||
RECORDING_ACTIVE = 'recording_active',
|
RECORDING_ACTIVE = 'recording_active',
|
||||||
SCHEDULED_TASK = 'scheduled_task'
|
SCHEDULED_TASK = 'scheduled_task',
|
||||||
|
GLOBAL_PREFERENCES = 'global_preferences',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export class MutexService {
|
|||||||
);
|
);
|
||||||
return lock;
|
return lock;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error('Error acquiring lock:', error);
|
this.logger.warn('Error acquiring lock:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,9 @@ import { errorRoomNotFound, OpenViduMeetError } from '../../models/error.model.j
|
|||||||
import { MEET_NAME_ID, MEET_SECRET, MEET_USER, MEET_WEBHOOK_ENABLED, MEET_WEBHOOK_URL } from '../../environment.js';
|
import { MEET_NAME_ID, MEET_SECRET, MEET_USER, MEET_WEBHOOK_ENABLED, MEET_WEBHOOK_URL } from '../../environment.js';
|
||||||
import { injectable, inject } from '../../config/dependency-injector.config.js';
|
import { injectable, inject } from '../../config/dependency-injector.config.js';
|
||||||
import { PasswordHelper } from '../../helpers/password.helper.js';
|
import { PasswordHelper } from '../../helpers/password.helper.js';
|
||||||
|
import { MutexService } from '../mutex.service.js';
|
||||||
|
import { MeetLock } from '../../helpers/redis.helper.js';
|
||||||
|
import ms from 'ms';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service for managing storage operations related to OpenVidu Meet rooms and preferences.
|
* A service for managing storage operations related to OpenVidu Meet rooms and preferences.
|
||||||
@ -21,7 +24,8 @@ export class MeetStorageService<G extends GlobalPreferences = GlobalPreferences,
|
|||||||
protected storageProvider: StorageProvider;
|
protected storageProvider: StorageProvider;
|
||||||
constructor(
|
constructor(
|
||||||
@inject(LoggerService) protected logger: LoggerService,
|
@inject(LoggerService) protected logger: LoggerService,
|
||||||
@inject(StorageFactory) protected storageFactory: StorageFactory
|
@inject(StorageFactory) protected storageFactory: StorageFactory,
|
||||||
|
@inject(MutexService) protected mutexService: MutexService
|
||||||
) {
|
) {
|
||||||
this.storageProvider = this.storageFactory.create();
|
this.storageProvider = this.storageFactory.create();
|
||||||
}
|
}
|
||||||
@ -30,16 +34,24 @@ export class MeetStorageService<G extends GlobalPreferences = GlobalPreferences,
|
|||||||
* Initializes default preferences if not already initialized.
|
* Initializes default preferences if not already initialized.
|
||||||
* @returns {Promise<G>} Default global preferences.
|
* @returns {Promise<G>} Default global preferences.
|
||||||
*/
|
*/
|
||||||
async buildAndSaveDefaultPreferences(): Promise<G> {
|
async initializeGlobalPreferences(): Promise<void> {
|
||||||
const preferences = await this.getDefaultPreferences();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Acquire a global lock to prevent multiple initializations at the same time when running in HA mode
|
||||||
|
const lock = await this.mutexService.acquire(MeetLock.getGlobalPreferencesLock(), ms('30s'));
|
||||||
|
|
||||||
|
if (!lock) {
|
||||||
|
this.logger.warn(
|
||||||
|
'Unable to acquire lock for global preferences initialization. May be already initialized by another instance.'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const preferences = await this.getDefaultPreferences();
|
||||||
|
|
||||||
this.logger.verbose('Initializing global preferences with default values');
|
this.logger.verbose('Initializing global preferences with default values');
|
||||||
await this.storageProvider.initialize(preferences);
|
await this.storageProvider.initialize(preferences);
|
||||||
return preferences as G;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.handleError(error, 'Error initializing default preferences');
|
this.handleError(error, 'Error initializing default preferences');
|
||||||
return Promise.resolve({} as G);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +64,9 @@ export class MeetStorageService<G extends GlobalPreferences = GlobalPreferences,
|
|||||||
|
|
||||||
if (preferences) return preferences as G;
|
if (preferences) return preferences as G;
|
||||||
|
|
||||||
return await this.buildAndSaveDefaultPreferences();
|
await this.initializeGlobalPreferences();
|
||||||
|
|
||||||
|
return this.storageProvider.getGlobalPreferences() as Promise<G>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user