Skip to content

Commit a31108e

Browse files
committed
FLS-1452 - Abstract Redis and Catbox cache clients in AdapterCacheService
This commit introduces a common interface attribute formStorage on the AdapterCacheService to represent either a Redis client or a Catbox (in-memory) cache client. This enables us to save significant lines of code, where previously we branched off to different functions depending on whether we were using Redis or not, now we can concentrate logic in fewer functions with no branching. We're able to do this because the way we use the two clients is almost identical since we no longer need getKeys functionality. Previously, because the Catbox cache client doesn't have a getKeys utility built-in like Redis, special code was required to keep track of the keys in the cache in the case of Catbox.
1 parent b65fb97 commit a31108e

File tree

2 files changed

+32
-105
lines changed

2 files changed

+32
-105
lines changed

runner/src/server/plugins/engine/MainPlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const plugin = {
1818
let countError = 0;
1919
for (const config of configs) {
2020
try {
21-
await adapterCacheService.setFormConfiguration(config.id, config, server);
21+
await adapterCacheService.setFormConfiguration(config.id, config);
2222
countOk++;
2323
} catch (e) {
2424
countError++;

runner/src/server/services/AdapterCacheService.ts

Lines changed: 31 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import Crypto from 'crypto';
1515
import {HapiRequest, HapiServer} from "../types";
1616
import {AdapterFormModel} from "../plugins/engine/models";
1717
import Boom from "boom";
18-
import {FormConfiguration} from "@xgovformbuilder/model";
19-
import {AdapterSchema} from "@communitiesuk/model";
2018

2119
const partition = "cache";
2220
const LOGGER_DATA = {
@@ -59,22 +57,26 @@ const createRedisClient = (): Redis | null => {
5957
};
6058

6159
export class AdapterCacheService extends CacheService {
60+
private formStorage: Redis | any;
6261

6362
constructor(server: HapiServer) {
6463
//@ts-ignore
6564
super(server);
66-
//@ts-ignore
67-
server.app.redis = this.getRedisClient()
68-
//@ts-ignore
69-
if (!server.app.redis) {
70-
// starting up the in memory cache
65+
const redisClient = this.getRedisClient();
66+
if (redisClient) {
67+
this.formStorage = redisClient;
68+
} else {
69+
// Starting up the in memory cache
7170
this.cache.client.start();
72-
//@ts-ignore
73-
server.app.inMemoryFormKeys = []
71+
this.formStorage = {
72+
get: (key) => this.cache.get(key),
73+
set: (key, value) => this.cache.set(key, value, {expiresIn: 0}),
74+
setex: (key, ttl, value) => this.cache.set(key, value, {expiresIn: ttl}),
75+
}
7476
}
7577
}
7678

77-
async activateSession(jwt, request) {
79+
async activateSession(jwt, request): Promise<{ redirectPath: string }> {
7880
request.logger.info(`[ACTIVATE-SESSION] jwt ${jwt}`);
7981
const initialisedSession = await this.cache.get(this.JWTKey(jwt));
8082
request.logger.info(`[ACTIVATE-SESSION] session details ${initialisedSession}`);
@@ -83,14 +85,12 @@ export class AdapterCacheService extends CacheService {
8385
const userSessionKey = {segment: partition, id: `${request.yar.id}:${payload.group}`};
8486
request.logger.info(`[ACTIVATE-SESSION] session metadata ${userSessionKey}`);
8587
const {redirectPath} = await super.activateSession(jwt, request);
86-
8788
let redirectPathNew = redirectPath
8889
const form_session_identifier = initialisedSession.metadata?.form_session_identifier;
8990
if (form_session_identifier) {
9091
userSessionKey.id = `${userSessionKey.id}:${form_session_identifier}`;
9192
redirectPathNew = `${redirectPathNew}?form_session_identifier=${form_session_identifier}`;
9293
}
93-
9494
if (config.overwriteInitialisedSession) {
9595
request.logger.info("[ACTIVATE-SESSION] Replacing user session with initialisedSession");
9696
this.cache.set(userSessionKey, initialisedSession, sessionTimeout);
@@ -120,7 +120,7 @@ export class AdapterCacheService extends CacheService {
120120
* @param additionalIdentifier - appended to the id
121121
*/
122122
//@ts-ignore
123-
Key(request: HapiRequest, additionalIdentifier?: ADDITIONAL_IDENTIFIER) {
123+
Key(request: HapiRequest, additionalIdentifier?: ADDITIONAL_IDENTIFIER): { segment: string; id: string } {
124124
let id = `${request.yar.id}:${request.params.id}`;
125125

126126
if (request.query.form_session_identifier) {
@@ -141,117 +141,44 @@ export class AdapterCacheService extends CacheService {
141141
* @param configuration form definition configurations
142142
* @param server server object
143143
*/
144-
async setFormConfiguration(formId: string, configuration: any, server: HapiServer) {
145-
if (formId && configuration) {
146-
//@ts-ignore
147-
if (server.app.redis) {
148-
await this.addConfigurationsToRedisCache(server, configuration, formId);
149-
} else {
150-
await this.addConfigurationIntoInMemoryCache(configuration, formId, server);
151-
}
152-
}
153-
}
154-
155-
private async addConfigurationIntoInMemoryCache(configuration: any, formId: string, server: HapiServer) {
156-
const hashValue = Crypto.createHash('sha256').update(JSON.stringify(configuration)).digest('hex')
144+
async setFormConfiguration(formId: string, configuration: any): Promise<void> {
145+
if (!formId || !configuration) return;
146+
const hashValue = Crypto.createHash('sha256')
147+
.update(JSON.stringify(configuration))
148+
.digest('hex');
149+
const key = `${FORMS_KEY_PREFIX}${formId}`;
157150
try {
158-
const jsonDataString = await this.cache.get(`${FORMS_KEY_PREFIX}${formId}`);
159-
if (jsonDataString === null) {
160-
// Adding new config into redis cache service with the hash value
151+
const existingConfigString = await this.formStorage.get(key);
152+
if (existingConfigString === null) {
153+
// Adding new config with the hash value
161154
const stringConfig = JSON.stringify({
162155
...configuration,
163156
id: configuration.id,
164157
hash: hashValue
165158
});
166-
//@ts-ignore
167-
server.app.inMemoryFormKeys.push(`${FORMS_KEY_PREFIX}${formId}`)
168-
// Adding data into redis cache
169-
await this.cache.set(`${FORMS_KEY_PREFIX}${formId}`, stringConfig, {expiresIn: 0});
159+
await this.formStorage.set(key, stringConfig);
170160
} else {
171-
// Redis has the data and gets current data set to check hash
172-
const configObj = JSON.parse(jsonDataString);
173-
if (configObj && configObj.hash && hashValue !== configObj.hash) {
174-
// if hash function is change then updating the configuration
161+
// Check if hash has changed
162+
const existingConfig = JSON.parse(existingConfigString);
163+
if (existingConfig?.hash !== hashValue) {
164+
// Hash has changed, update the configuration
175165
const stringConfig = JSON.stringify({
176166
...configuration,
177167
id: configuration.id,
178168
hash: hashValue
179169
});
180-
await this.cache.set(`${FORMS_KEY_PREFIX}${formId}`, stringConfig, {expiresIn: 0});
170+
await this.formStorage.set(key, stringConfig);
181171
}
182172
}
183173
} catch (error) {
184174
console.log(error);
185175
}
186176
}
187177

188-
private async addConfigurationsToRedisCache(server: HapiServer, configuration: any, formId: string) {
189-
//@ts-ignore
190-
const redisClient: Redis = server.app.redis
191-
const hashValue = Crypto.createHash('sha256').update(JSON.stringify(configuration)).digest('hex')
192-
if (redisClient) {
193-
const jsonDataString = await redisClient.get(`${FORMS_KEY_PREFIX}${formId}`);
194-
if (jsonDataString === null) {
195-
// Adding new config into redis cache service with the hash value
196-
const stringConfig = JSON.stringify({
197-
...configuration,
198-
id: configuration.id,
199-
hash: hashValue
200-
});
201-
// Adding data into redis cache
202-
await redisClient.set(`${FORMS_KEY_PREFIX}${formId}`, stringConfig);
203-
} else {
204-
// Redis has the data and gets current data set to check hash
205-
const configObj = JSON.parse(jsonDataString);
206-
if (configObj && configObj.hash && hashValue !== configObj.hash) {
207-
// if hash function is change then updating the configuration
208-
const stringConfig = JSON.stringify({
209-
...configuration,
210-
id: configuration.id,
211-
hash: hashValue
212-
});
213-
await redisClient.set(`${FORMS_KEY_PREFIX}${formId}`, stringConfig);
214-
}
215-
}
216-
}
217-
}
218-
219-
async getFormAdapterModel(formId: string, request: HapiRequest) {
220-
//@ts-ignore
221-
if (request.server.app.redis) {
222-
return await this.getConfigurationFromRedisCache(request, formId);
223-
} else {
224-
return await this.getConfigurationFromInMemoryCache(request, formId);
225-
}
226-
}
227-
228-
private async getConfigurationFromInMemoryCache(request: HapiRequest, formId: string) {
229-
const {translationLoaderService} = request.services([]);
230-
const translations = translationLoaderService.getTranslations();
231-
const jsonDataString = await this.cache.get(`${FORMS_KEY_PREFIX}${formId}`);
232-
if (jsonDataString !== null) {
233-
const configObj = JSON.parse(jsonDataString);
234-
return new AdapterFormModel(configObj.configuration, {
235-
basePath: configObj.id ? configObj.id : formId,
236-
hash: configObj.hash,
237-
previewMode: true,
238-
translationEn: translations.en,
239-
translationCy: translations.cy
240-
})
241-
}
242-
request.logger.error({
243-
...LOGGER_DATA,
244-
message: `[FORM-CACHE] Cannot find the form ${formId}`
245-
});
246-
throw Boom.notFound("Cannot find the given form");
247-
}
248-
249-
private async getConfigurationFromRedisCache(request: HapiRequest, formId: string) {
250-
//@ts-ignore
251-
const redisClient: Redis = request.server.app.redis
178+
async getFormAdapterModel(formId: string, request: HapiRequest): Promise<AdapterFormModel> {
252179
const {translationLoaderService} = request.services([]);
253180
const translations = translationLoaderService.getTranslations();
254-
const jsonDataString = await redisClient.get(`${FORMS_KEY_PREFIX}${formId}`);
181+
const jsonDataString = await this.formStorage.get(`${FORMS_KEY_PREFIX}${formId}`);
255182
if (jsonDataString !== null) {
256183
const configObj = JSON.parse(jsonDataString);
257184
return new AdapterFormModel(configObj.configuration, {
@@ -260,7 +187,7 @@ export class AdapterCacheService extends CacheService {
260187
previewMode: true,
261188
translationEn: translations.en,
262189
translationCy: translations.cy
263-
})
190+
});
264191
}
265192
request.logger.error({
266193
...LOGGER_DATA,

0 commit comments

Comments
 (0)