fix async preference bug

This commit is contained in:
rubikscraft 2022-04-14 11:25:39 +02:00
parent 65cff6f276
commit 5f81a577f1
No known key found for this signature in database
GPG key ID: 3570A2BB18A63D9F
5 changed files with 50 additions and 41 deletions

View file

@ -30,7 +30,6 @@ export class PreferenceDefaultsService {
if (envSecret) {
return envSecret;
} else {
console.trace(`what`);
this.logger.warn(
'Since no JWT secret was provided, a random one will be generated and saved',
);

View file

@ -3,16 +3,20 @@ import { InjectRepository } from '@nestjs/typeorm';
import {
DecodedSysPref,
PrefValueType,
PrefValueTypeStrings
PrefValueTypeStrings,
} from 'picsur-shared/dist/dto/preferences.dto';
import { SysPreference } from 'picsur-shared/dist/dto/syspreferences.dto';
import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
import { Repository } from 'typeorm';
import {
SysPreferenceList,
SysPreferenceValueTypes
SysPreferenceValueTypes,
} from '../../models/dto/syspreferences.dto';
import { ESysPreferenceBackend, ESysPreferenceSchema } from '../../models/entities/syspreference.entity';
import {
ESysPreferenceBackend,
ESysPreferenceSchema,
} from '../../models/entities/syspreference.entity';
import { FallBackMutex } from '../../models/util/FallBackMutex';
import { PreferenceCommonService } from './preferencecommon.service';
import { PreferenceDefaultsService } from './preferencedefaults.service';
@ -57,29 +61,25 @@ export class SysPreferenceService {
public async getPreference(key: string): AsyncFailable<DecodedSysPref> {
// Validate
let validatedKey = this.prefCommon.validatePrefKey(
key,
SysPreference,
);
let validatedKey = this.prefCommon.validatePrefKey(key, SysPreference);
if (HasFailed(validatedKey)) return validatedKey;
// Fetch
let foundSysPreference: ESysPreferenceBackend | null;
let foundSysPreference: ESysPreferenceBackend;
try {
foundSysPreference = await this.sysPreferenceRepository.findOne({
where: { key: validatedKey },
cache: 60000,
});
foundSysPreference = await FallBackMutex(
'fetchSysPrefrence',
() =>
this.sysPreferenceRepository.findOne({
where: { key: validatedKey as SysPreference },
cache: 60000,
}),
() => this.saveDefault(validatedKey as SysPreference),
);
} catch (e: any) {
this.logger.warn(e);
return Fail('Could not get preference');
}
// Fallback
if (!foundSysPreference) {
return this.saveDefault(validatedKey);
}
// Validate
const result = ESysPreferenceSchema.safeParse(foundSysPreference);
if (!result.success) {

View file

@ -3,19 +3,20 @@ import { InjectRepository } from '@nestjs/typeorm';
import {
DecodedUsrPref,
PrefValueType,
PrefValueTypeStrings
PrefValueTypeStrings,
} from 'picsur-shared/dist/dto/preferences.dto';
import { UsrPreference } from 'picsur-shared/dist/dto/usrpreferences.dto';
import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
import { Repository } from 'typeorm';
import {
UsrPreferenceList,
UsrPreferenceValueTypes
UsrPreferenceValueTypes,
} from '../../models/dto/usrpreferences.dto';
import {
EUsrPreferenceBackend,
EUsrPreferenceSchema
EUsrPreferenceSchema,
} from '../../models/entities/usrpreference.entity';
import { FallBackMutex } from '../../models/util/FallBackMutex';
import { PreferenceCommonService } from './preferencecommon.service';
import { PreferenceDefaultsService } from './preferencedefaults.service';
@ -68,23 +69,22 @@ export class UsrPreferenceService {
let validatedKey = this.prefCommon.validatePrefKey(key, UsrPreference);
if (HasFailed(validatedKey)) return validatedKey;
// Fetch
let foundUsrPreference: EUsrPreferenceBackend | null;
let foundUsrPreference: EUsrPreferenceBackend;
try {
foundUsrPreference = await this.usrPreferenceRepository.findOne({
where: { key: validatedKey, userId: userid },
cache: 60000,
});
foundUsrPreference = await FallBackMutex(
'fetchUsrPrefrence',
() =>
this.usrPreferenceRepository.findOne({
where: { key: validatedKey as UsrPreference, userId: userid },
cache: 60000,
}),
() => this.saveDefault(userid, validatedKey as UsrPreference),
);
} catch (e: any) {
this.logger.warn(e);
return Fail('Could not get preference');
}
// Fallback
if (!foundUsrPreference) {
return this.saveDefault(userid, validatedKey);
}
// Validate
const result = EUsrPreferenceSchema.safeParse(foundUsrPreference);
if (!result.success) {

View file

@ -1,14 +1,24 @@
import { AsyncFailable, HasSuccess } from 'picsur-shared/dist/types';
/*
This function is necessary to make sure that a default isnt generated multiple times at the same time.
Doing that will cause errors.
An example is the jwt secret value, its value is requested aroun 3 times at the same time while starting.
So when the program was started for the first time, each request returned a different secret.
This function will first try and see if its first function returns a value, if it does, it will return that value.
If not it will execute a fallback function, which usually is a function that populates a default value.
After that is done it will retry the first function again.
*/
const fallBackMap: Record<string, Promise<unknown>> = {};
export async function FallBackMutex<
MF extends () => AsyncFailable<O>,
FF extends () => AsyncFailable<unknown>,
MF extends () => Promise<O | null | undefined>,
FF extends () => Promise<unknown>,
O,
>(key: string, mainFunc: MF, fallBackFunc: FF): AsyncFailable<O> {
>(key: string, mainFunc: MF, fallBackFunc: FF): Promise<O> {
const try_it = await mainFunc();
if (HasSuccess(try_it)) return try_it;
if (try_it !== undefined && try_it !== null) return try_it;
if (fallBackMap[key] !== undefined) {
await fallBackMap[key];

View file

@ -4,7 +4,7 @@ import {
Get,
InternalServerErrorException,
Logger,
Post
Post,
} from '@nestjs/common';
import {
GetSpecialUsersResponse,
@ -17,7 +17,7 @@ import {
UserListRequest,
UserListResponse,
UserUpdateRequest,
UserUpdateResponse
UserUpdateResponse,
} from 'picsur-shared/dist/dto/api/usermanage.dto';
import { HasFailed } from 'picsur-shared/dist/types';
import { UsersService } from '../../../collections/userdb/userdb.service';
@ -27,7 +27,7 @@ import { Permission } from '../../../models/dto/permissions.dto';
import {
ImmutableUsersList,
LockedLoginUsersList,
UndeletableUsersList
UndeletableUsersList,
} from '../../../models/dto/specialusers.dto';
import { EUserBackend2EUser } from '../../../models/transformers/user.transformer';