import { Injectable, Logger } from '@nestjs/common'; import { Users } from '../couchdb-datasources/users'; import { RedmineDataLoader } from '../redmine-data-loader/redmine-data-loader'; import { RedmineUserCacheWriterService } from '../user-cache-writer/user-cache-writer.service'; import { RedmineTypes } from '../models/redmine-types'; import { MemoryCache } from '../utils/memory-cache'; export const USER_MEMORY_CACHE_LIFETIME = 24 * 60 * 60 * 1000; const USER_MEMORY_CACHE_AUTOCLEAN_INTERVAL = 1000 * 60 * 5; @Injectable() export class UsersService { private logger = new Logger(UsersService.name); private memoryCache = new MemoryCache( USER_MEMORY_CACHE_LIFETIME, USER_MEMORY_CACHE_AUTOCLEAN_INTERVAL, ); constructor( private users: Users, private redmineDataLoader: RedmineDataLoader, private redmineUserCacheWriterService: RedmineUserCacheWriterService, ) {} async getUser(userId: number): Promise { const userFromMemoryCache = this.getUserFromMemoryCache(userId); if (userFromMemoryCache) { return RedmineTypes.CreatePublicUserFromUser(userFromMemoryCache); } const userFromCache = await this.getUserFromCache(userId); if (userFromCache) { this.memoryCache.set(userId, userFromCache); return RedmineTypes.CreatePublicUserFromUser(userFromCache); } let userFromRedmine = await this.getUserFromRedmine(userId); if (userFromRedmine) { userFromRedmine = await this.redmineUserCacheWriterService.saveUser( userFromRedmine, ); } return RedmineTypes.CreatePublicUserFromUser( this.memoryCache.set( userId, userFromRedmine || RedmineTypes.Unknown.user, ), ); } private async getUserFromRedmine( userId: number, ): Promise { const user = await this.redmineDataLoader.loadUser(userId); if (user) { this.logger.debug( `Get user from redmine with userId = ${userId}, login = ${user.login}`, ); } return user; } private async getUserFromCache( userId: number, ): Promise { const usersDb = await this.users.getDatasource(); try { const user = (await usersDb.get(String(userId))) as any; this.logger.debug( `Get user from couchdb with userId = ${userId}, login = ${user.login}`, ); return user; } catch (ex) { return null; } } private getUserFromMemoryCache(userId: number): RedmineTypes.User | null { const user = this.memoryCache.get(userId); if (user) { this.logger.debug( `Get user from memory cache with userId = ${userId}, login = ${user.login}`, ); } return user; } }