Skip to content

Commit

Permalink
feat: implement api-cache-data-access module for api caching
Browse files Browse the repository at this point in the history
  • Loading branch information
beeman committed Dec 14, 2022
1 parent 91d421f commit 75ebd85
Show file tree
Hide file tree
Showing 20 changed files with 328 additions and 9 deletions.
10 changes: 10 additions & 0 deletions libs/api/cache/data-access/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"presets": [
[
"@nrwl/web/babel",
{
"useBuiltIns": "usage"
}
]
]
}
18 changes: 18 additions & 0 deletions libs/api/cache/data-access/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
7 changes: 7 additions & 0 deletions libs/api/cache/data-access/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# api-cache-data-access

This library was generated with [Nx](https://nx.dev).

## Running unit tests

Run `nx test api-cache-data-access` to execute the unit tests via [Jest](https://jestjs.io).
16 changes: 16 additions & 0 deletions libs/api/cache/data-access/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable */
export default {
displayName: 'api-cache-data-access',
preset: '../../../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
},
},
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../../../coverage/libs/api/cache/data-access',
}
24 changes: 24 additions & 0 deletions libs/api/cache/data-access/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "api-cache-data-access",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/api/cache/data-access/src",
"projectType": "library",
"targets": {
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/api/cache/data-access/**/*.ts"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/api/cache/data-access/jest.config.ts",
"passWithNoTests": true
}
}
},
"tags": ["scope:api", "type:data-access"]
}
2 changes: 2 additions & 0 deletions libs/api/cache/data-access/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './lib/api-cache-data-access.service'
export * from './lib/api-cache-data-access.module'
26 changes: 26 additions & 0 deletions libs/api/cache/data-access/src/lib/api-cache-data-access.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ApiConfigDataAccessModule, ApiConfigDataAccessService } from '@kin-kinetic/api/config/data-access'
import { CacheModule, Module } from '@nestjs/common'
import * as redisStore from 'cache-manager-redis-store'

import { ApiCacheDataAccessService } from './api-cache-data-access.service'

@Module({
imports: [
CacheModule.registerAsync({
imports: [ApiConfigDataAccessModule],
inject: [ApiConfigDataAccessService],
isGlobal: false,
useFactory: (cfg) => ({
store: redisStore,
host: cfg.redisHost,
port: cfg.redisPort,
username: cfg.redisUsername,
password: cfg.redisPassword,
ttl: 5,
}),
}),
],
providers: [ApiCacheDataAccessService],
exports: [ApiCacheDataAccessService],
})
export class ApiCacheDataAccessModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { CacheModule } from '@nestjs/common'
import { Test } from '@nestjs/testing'
import { ApiCacheDataAccessService } from './api-cache-data-access.service'

describe('ApiCacheDataAccessService', () => {
let service: ApiCacheDataAccessService

beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [CacheModule.register({})],
providers: [ApiCacheDataAccessService],
}).compile()

service = module.get(ApiCacheDataAccessService)
})

it('should be defined', () => {
expect(service).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CACHE_MANAGER, Inject, Injectable, Logger } from '@nestjs/common'
import { style } from '@ogma/styler'
import { Cache } from 'cache-manager'

export type CacheNamespace = 'solana'

export function getCacheKey(namespace: CacheNamespace, key: string) {
return `kinetic:${namespace}:${key}`
}

@Injectable()
export class ApiCacheDataAccessService {
private readonly logger = new Logger(ApiCacheDataAccessService.name)
constructor(@Inject(CACHE_MANAGER) private readonly cache: Cache) {}

del(namespace: CacheNamespace, key: string) {
return this.cache.del(getCacheKey(namespace, key))
}

/**
* Get a value from the cache, or set it if it doesn't exist.
*/
async wrap<T>(namespace: CacheNamespace, key: string, fn: () => Promise<T>, ttl?: number): Promise<T> {
const cacheKey = getCacheKey(namespace, key)
const found = await this.get<T>(namespace, key)
if (!found) {
const result = await fn()
await this.set<T>(namespace, key, result, ttl)
this.logger.verbose(`${style.bYellow.apply('[CACHE MISS]')} ${cacheKey} ttl=${ttl} seconds`)
return result
}

this.logger.verbose(`${style.bGreen.apply('[CACHE HIT]')} ${cacheKey} ttl=${ttl} seconds`)
return found
}

/**
* Get a value from the cache based on the namespace and key.
*/
private get<T>(namespace: CacheNamespace, key: string) {
return this.cache.get<T>(getCacheKey(namespace, key))
}

/**
* Set a value in the cache based on the namespace and key.
*/
private set<T>(namespace: CacheNamespace, key: string, value: T, ttl?: number) {
return this.cache.set<T>(getCacheKey(namespace, key), value, { ttl: ttl ?? 5 })
}
}
16 changes: 16 additions & 0 deletions libs/api/cache/data-access/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs"
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
11 changes: 11 additions & 0 deletions libs/api/cache/data-access/tsconfig.lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"],
"target": "es6"
},
"include": ["**/*.ts"],
"exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"]
}
9 changes: 9 additions & 0 deletions libs/api/cache/data-access/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ApiCacheDataAccessModule } from '@kin-kinetic/api/cache/data-access'
import { ApiConfigDataAccessModule } from '@kin-kinetic/api/config/data-access'
import { Module } from '@nestjs/common'
import { OpenTelemetryCoreModule } from 'nestjs-otel/lib/opentelemetry-core.module'
import { ApiCoreDataAccessService } from './api-core-data-access.service'

@Module({
imports: [ApiConfigDataAccessModule, OpenTelemetryCoreModule.forRoot()],
imports: [ApiCacheDataAccessModule, ApiConfigDataAccessModule, OpenTelemetryCoreModule.forRoot()],
providers: [ApiCoreDataAccessService],
exports: [ApiCoreDataAccessService],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiCacheDataAccessModule } from '@kin-kinetic/api/cache/data-access'
import { ApiConfigDataAccessModule } from '@kin-kinetic/api/config/data-access'
import { Test } from '@nestjs/testing'
import { OpenTelemetryCoreModule } from 'nestjs-otel/lib/opentelemetry-core.module'
Expand All @@ -8,7 +9,7 @@ describe('ApiCoreDataAccessService', () => {

beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [ApiConfigDataAccessModule, OpenTelemetryCoreModule.forRoot()],
imports: [ApiCacheDataAccessModule, ApiConfigDataAccessModule, OpenTelemetryCoreModule.forRoot()],
providers: [ApiCoreDataAccessService],
}).compile()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AirdropConfig } from '@kin-kinetic/api/airdrop/util'
import { hashPassword } from '@kin-kinetic/api/auth/util'
import { ApiCacheDataAccessService } from '@kin-kinetic/api/cache/data-access'
import { ProvisionedCluster } from '@kin-kinetic/api/cluster/util'
import { ApiConfigDataAccessService } from '@kin-kinetic/api/config/data-access'
import { parseAppKey } from '@kin-kinetic/api/core/util'
Expand Down Expand Up @@ -38,7 +39,11 @@ export class ApiCoreDataAccessService extends PrismaClient implements OnModuleIn
private getAppByEnvironmentIndexCounter: Counter
private getAppByIndexCounter: Counter

constructor(readonly config: ApiConfigDataAccessService, readonly metrics: MetricService) {
constructor(
readonly cache: ApiCacheDataAccessService,
readonly config: ApiConfigDataAccessService,
readonly metrics: MetricService,
) {
super()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ApiQueueCloseAccountModule } from './queue/close-account/api-queue-clos
imports: [ApiConfigDataAccessModule],
useFactory: async (config: ApiConfigDataAccessService) => ({
redis: config.redisConfig,
prefix: 'kinetic:queue',
}),
inject: [ApiConfigDataAccessService],
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ApiCoreDataAccessModule } from '@kin-kinetic/api/core/data-access'
import { Module } from '@nestjs/common'

import { ApiSolanaDataAccessService } from './api-solana-data-access.service'

@Module({
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
"bcrypt": "^5.1.0",
"bignumber": "^1.1.0",
"bull": "^4.10.2",
"cache-manager": "^4.1.0",
"cache-manager-redis-store": "2.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"color": "^4.2.3",
Expand Down Expand Up @@ -122,6 +124,7 @@
"react-router-dom": "6.4.1",
"react-timeago": "^7.1.0",
"redirect-ssl": "^3.0.0",
"redis": "^4.5.1",
"reflect-metadata": "^0.1.13",
"regenerator-runtime": "^0.13.10",
"request-ip": "^3.3.0",
Expand Down
1 change: 1 addition & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@kin-kinetic/api/auth/data-access": ["libs/api/auth/data-access/src/index.ts"],
"@kin-kinetic/api/auth/feature": ["libs/api/auth/feature/src/index.ts"],
"@kin-kinetic/api/auth/util": ["libs/api/auth/util/src/index.ts"],
"@kin-kinetic/api/cache/data-access": ["libs/api/cache/data-access/src/index.ts"],
"@kin-kinetic/api/cluster/data-access": ["libs/api/cluster/data-access/src/index.ts"],
"@kin-kinetic/api/cluster/feature": ["libs/api/cluster/feature/src/index.ts"],
"@kin-kinetic/api/cluster/util": ["libs/api/cluster/util/src/index.ts"],
Expand Down
Loading

0 comments on commit 75ebd85

Please sign in to comment.