mirror of https://github.com/ghostfolio/ghostfolio
Browse Source
* Fix portfolio snapshot cache write and initialization retry limit * Update changelogpull/7501/head
committed by
GitHub
28 changed files with 146 additions and 11 deletions
@ -0,0 +1,7 @@ |
|||
export class PortfolioSnapshotComputationError extends Error { |
|||
public constructor(message: string) { |
|||
super(message); |
|||
|
|||
this.name = 'PortfolioSnapshotComputationError'; |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
import { PortfolioSnapshotComputationError } from '@ghostfolio/api/app/portfolio/errors/portfolio-snapshot-computation.error'; |
|||
|
|||
import { ArgumentsHost, Catch, ExceptionFilter, Logger } from '@nestjs/common'; |
|||
import { Response } from 'express'; |
|||
import { getReasonPhrase, StatusCodes } from 'http-status-codes'; |
|||
|
|||
@Catch(PortfolioSnapshotComputationError) |
|||
export class PortfolioSnapshotComputationExceptionFilter implements ExceptionFilter { |
|||
private readonly logger = new Logger( |
|||
PortfolioSnapshotComputationExceptionFilter.name |
|||
); |
|||
|
|||
public catch( |
|||
exception: PortfolioSnapshotComputationError, |
|||
host: ArgumentsHost |
|||
) { |
|||
this.logger.error(exception.message); |
|||
|
|||
const response = host.switchToHttp().getResponse<Response>(); |
|||
|
|||
response.status(StatusCodes.SERVICE_UNAVAILABLE).json({ |
|||
message: getReasonPhrase(StatusCodes.SERVICE_UNAVAILABLE), |
|||
statusCode: StatusCodes.SERVICE_UNAVAILABLE |
|||
}); |
|||
} |
|||
} |
|||
@ -1,32 +1,47 @@ |
|||
import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface'; |
|||
import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; |
|||
|
|||
import type { Job, JobId, JobOptions } from 'bull'; |
|||
import ms from 'ms'; |
|||
import { setTimeout } from 'timers/promises'; |
|||
|
|||
import { PortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue-job.interface'; |
|||
|
|||
export const PortfolioSnapshotServiceMock = { |
|||
addJobToQueue({ |
|||
addJobToQueue: ({ |
|||
opts |
|||
}: { |
|||
data: PortfolioSnapshotQueueJob; |
|||
name: string; |
|||
opts?: JobOptions; |
|||
}): Promise<Job> { |
|||
}): Promise<Job> => { |
|||
const mockJob: Partial<Job> = { |
|||
finished: async () => { |
|||
await setTimeout(100); |
|||
|
|||
return Promise.resolve(); |
|||
// Mimic the processor which caches the computed portfolio snapshot
|
|||
// under the job id
|
|||
await RedisCacheServiceMock.set( |
|||
opts?.jobId as string, |
|||
JSON.stringify({ |
|||
expiration: Date.now() + ms('1 minute'), |
|||
portfolioSnapshot: {} |
|||
} as unknown as PortfolioSnapshotValue) |
|||
); |
|||
} |
|||
}; |
|||
|
|||
this.jobsStore.set(opts?.jobId, mockJob); |
|||
PortfolioSnapshotServiceMock.jobsStore.set(opts?.jobId, mockJob); |
|||
|
|||
return Promise.resolve(mockJob as Job); |
|||
}, |
|||
getJob(jobId: JobId): Promise<Job> { |
|||
const job = this.jobsStore.get(jobId); |
|||
getJob: (jobId: JobId): Promise<Job> => { |
|||
const job = PortfolioSnapshotServiceMock.jobsStore.get(jobId); |
|||
|
|||
return Promise.resolve(job as Job); |
|||
}, |
|||
jobsStore: new Map<JobId, Partial<Job>>() |
|||
jobsStore: new Map<JobId, Partial<Job>>(), |
|||
reset: () => { |
|||
PortfolioSnapshotServiceMock.jobsStore.clear(); |
|||
} |
|||
}; |
|||
|
|||
Loading…
Reference in new issue