Skip to content

Commit 21616a0

Browse files
committed
🐛 set cache state to cached after fetching
1 parent 38f92d1 commit 21616a0

File tree

5 files changed

+57
-72
lines changed

5 files changed

+57
-72
lines changed

src/cache/storage-cache.ts

Lines changed: 40 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class StorageCache implements ContactCache {
1818
this.storage = storageAdapter;
1919

2020
const { CACHE_REFRESH_INTERVAL } = process.env;
21+
2122
if (CACHE_REFRESH_INTERVAL) {
2223
this.cacheRefreshIntervalMs =
2324
Math.max(Number(CACHE_REFRESH_INTERVAL), 1) * 1000;
@@ -34,49 +35,35 @@ export class StorageCache implements ContactCache {
3435
key: string,
3536
getFreshValue?: (key: string) => Promise<Contact[]>
3637
): Promise<Contact[] | CacheItemState> {
38+
const anonKey = anonymizeKey(key);
39+
3740
try {
38-
this.log(`[${anonymizeKey(key)}] Trying to get Contacts from cache`);
39-
const start = performance.now();
41+
this.log(`[${anonKey}] Trying to get contacts from cache`);
42+
4043
const cacheItemState = await this.storage.get<CacheItemState>(
4144
this.getCacheItemKey(key)
4245
);
4346

44-
const value = await this.storage.get<Contact[]>(key);
45-
console.log(
46-
`[${anonymizeKey(key)}] loading contacts took ${
47-
performance.now() - start
48-
}ms`
49-
);
47+
const contacts = await this.storage.get<Contact[]>(key);
5048

51-
if (
52-
cacheItemState &&
53-
cacheItemState.state === CacheItemStateType.FETCHING
54-
) {
49+
if (cacheItemState?.state === CacheItemStateType.FETCHING) {
5550
this.log(
56-
`[${anonymizeKey(
57-
key
58-
)}] Not refreshing for because fetching is already in progress.`
51+
`[${anonKey}] Not refreshing contacts, because cache state is FETCHING`
5952
);
6053

6154
// if we have old contacts saved in cache we return them instead
62-
if (value && value.length > 0) {
55+
if (contacts && contacts?.length > 0) {
6356
this.log(
64-
`[${anonymizeKey(key)}] Returning previously cached contacts (${
65-
value.length
66-
}), because new contacts are still being fetched.`
57+
`[${anonKey}] Returning previously cached contacts (${contacts.length}), because new contacts are still being fetched`
6758
);
68-
return value;
59+
return contacts;
6960
}
7061

7162
return cacheItemState;
7263
}
7364

74-
if (value) {
75-
this.log(
76-
`[${anonymizeKey(key)}] Found contacts ${
77-
value.length
78-
} for key in cache.`
79-
);
65+
if (contacts) {
66+
this.log(`[${anonKey}] Found ${contacts.length} contacts in cache`);
8067

8168
const now: number = new Date().getTime();
8269

@@ -88,65 +75,59 @@ export class StorageCache implements ContactCache {
8875

8976
if (getFreshValue && isValueStale) {
9077
this.log(
91-
`[${anonymizeKey(key)}] value was stale, fetching fresh contacts`
78+
`[${anonKey}] cached value was stale, fetching fresh contacts`
9279
);
9380
// we don't return the fresh value here because we don't want to wait on the result.
9481
// We return the old value instead, the fresh value is returned the next time it is requested
9582
this.getRefreshed(key, getFreshValue).catch((error) => {
96-
this.logErr(
97-
`[${anonymizeKey(
98-
key
99-
)}] Unable to get fresh values, error was ${error}`
100-
);
83+
this.logErr(`[${anonKey}] Unable to get fresh contacts`, error);
10184
});
10285
}
10386

104-
return value;
87+
return contacts;
10588
}
10689
} catch (e) {
107-
this.logErr(`[${anonymizeKey(key)}] Unable to get cache".`, e);
90+
this.logErr(`[${anonKey}] Unable to get cache".`, e);
10891
}
10992

11093
if (!getFreshValue) {
11194
this.log(
112-
`[${anonymizeKey(
113-
key
114-
)}] No getFreshValue function provided. Returning empty array.`
95+
`[${anonKey}] No getFreshValue function provided - returning empty array`
11596
);
11697
return [];
11798
}
11899

119-
this.log(
120-
`[${anonymizeKey(key)}] Found no match in cache. Getting fresh value.`
121-
);
100+
this.log(`[${anonKey}] Found no match in cache. Getting fresh value.`);
122101
return this.getRefreshed(key, getFreshValue);
123102
}
124103

125-
public async set(key: string, value: Contact[]): Promise<void> {
126-
this.log(
127-
`[${anonymizeKey(key)}] Saving ${value.length} contacts to cache.`
128-
);
104+
public async set(key: string, contacts: Contact[]): Promise<void> {
105+
const anonKey = anonymizeKey(key);
106+
this.log(`[${anonKey}] Saving ${contacts.length} contacts to cache`);
129107
try {
130-
await this.storage.set(key, value);
108+
await this.storage.set(key, contacts);
131109
} catch (e) {
132-
this.logErr(`[${anonymizeKey(key)}] Unable to set cache.`, e);
110+
this.logErr(`[${anonKey}] Unable to set cache`, e);
133111
}
134112
}
135113

136114
public async delete(key: string): Promise<void> {
137-
this.log(`[${anonymizeKey(key)}] Removing contacts from cache.`);
115+
const anonKey = anonymizeKey(key);
116+
this.log(`[${anonKey}] Removing contacts from cache`);
138117
try {
139118
await this.storage.delete(key);
140119
} catch (e) {
141-
this.logErr(`[${anonymizeKey(key)}] Unable to delete cache`, e);
120+
this.logErr(`[${anonKey}] Unable to delete cache`, e);
142121
}
143122
}
144123

145124
private async getRefreshed(
146125
key: string,
147126
getFreshValue: (key: string) => Promise<Contact[]>
148127
): Promise<Contact[]> {
149-
this.log(`[${anonymizeKey(key)}] Refreshing value…`);
128+
const anonKey = anonymizeKey(key);
129+
130+
this.log(`[${anonKey}] Setting cache state to FETCHING`);
150131

151132
await this.storage.set<CacheItemState>(
152133
this.getCacheItemKey(key),
@@ -159,13 +140,19 @@ export class StorageCache implements ContactCache {
159140
try {
160141
const freshValue = await getFreshValue(key);
161142

162-
if (freshValue) {
163-
await this.set(key, freshValue);
164-
}
143+
await this.set(key, freshValue);
144+
145+
this.log(`[${anonKey}] Setting cache state to CACHED`);
146+
147+
await this.storage.set<CacheItemState>(this.getCacheItemKey(key), {
148+
state: CacheItemStateType.CACHED,
149+
updated: Date.now(),
150+
});
165151

166152
return freshValue;
167153
} catch (error) {
168-
this.log(`[${anonymizeKey(key)}] Error while refreshing value`, error);
154+
this.log(`[${anonKey}] Error while refreshing value`, error);
155+
await this.storage.delete(this.getCacheItemKey(key));
169156
throw error;
170157
}
171158
}

src/cache/storage/memory-storage-adapter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ export class MemoryStorageAdapter implements StorageAdapter {
1717
sizeCalculation: sizeof,
1818
});
1919

20-
console.log(`[CACHE] Initialized Memory storage`);
20+
console.log(`Initialized memory cache`);
2121
}
2222

2323
public async get<T>(key: string): Promise<T | null> {
24-
const cached = this.cache.get(key) as T;
25-
return cached ? cached : null;
24+
const cached = await this.cache.get<T>(key);
25+
return cached ?? null;
2626
}
2727

2828
public async set<T>(key: string, value: T): Promise<void> {

src/cache/storage/redis-storage-adapter.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,35 @@ export class RedisStorageAdapter implements StorageAdapter {
2121
console.log(`Initialized Redis storage with URL ${url}`);
2222

2323
this.client.on("error", (error) => {
24-
console.warn("Redis error: ", error.message);
24+
console.error("Redis error: ", error.message);
2525
});
2626

2727
this.client.on("ready", () => {
28-
console.info("Redis is ready.");
28+
console.info("Redis is ready");
2929
});
3030

3131
this.client.on("reconnecting", () => {
32-
console.warn("Redis is reconnecting.");
32+
console.warn("Redis is reconnecting");
3333
});
3434

3535
this.client
3636
.connect()
3737
.then(() => {
38-
console.info("Redis successfully connected.");
38+
console.info("Redis successfully connected");
3939
})
4040
.catch((error) => {
4141
console.warn("Redis connection error: ", error.message);
4242
});
4343
}
4444

4545
public async get<T>(key: string): Promise<T | null> {
46-
try {
47-
const value = await this.client.get(key);
48-
if (!value) {
49-
return null;
50-
}
51-
const decompressed = await inflate(Buffer.from(value, "base64"));
52-
const result = JSON.parse(decompressed.toString());
53-
return result;
54-
} catch {
46+
const value = await this.client.get(key);
47+
if (!value) {
5548
return null;
5649
}
50+
const decompressed = await inflate(Buffer.from(value, "base64"));
51+
const result = JSON.parse(decompressed.toString());
52+
return result;
5753
}
5854

5955
public async set<T>(key: string, value: T, ttl?: number): Promise<void> {

src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import cors from "cors";
44
import express from "express";
55
import { Server } from "http";
66
import { errorHandlerMiddleware, extractHeaderMiddleware } from "./middlewares";
7-
import { Adapter, Controller } from "./models";
7+
import { Adapter, ContactCache, Controller } from "./models";
88
import { CustomRouter } from "./models/custom-router.model";
99
import { getContactCache } from "./util/get-contact-cache";
1010

@@ -22,12 +22,14 @@ app.use(
2222
app.use(bodyParser.json());
2323
app.use(extractHeaderMiddleware);
2424

25-
const cache = getContactCache();
25+
let cache: ContactCache | null = null;
2626

2727
export function start(
2828
adapter: Adapter,
2929
customRouters: CustomRouter[] = []
3030
): Server {
31+
cache = getContactCache();
32+
3133
const controller: Controller = new Controller(adapter, cache);
3234

3335
app.get("/contacts", (req, res, next) =>

src/util/get-contact-cache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export function getContactCache(): ContactCache | null {
1111
}
1212

1313
if (REDIS_URL) {
14-
console.log("[CACHE] Using redis cache");
14+
console.log("[CACHE] Using Redis cache");
1515
return new StorageCache(new RedisStorageAdapter(REDIS_URL));
1616
}
1717

0 commit comments

Comments
 (0)