forked from ritik4ever/stellar-goal-vault
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache.ts
More file actions
162 lines (141 loc) · 3.36 KB
/
Copy pathcache.ts
File metadata and controls
162 lines (141 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import { createClient, RedisClientType } from 'redis';
type RedisClient = RedisClientType;
let redisClient: RedisClient | null = null;
let isConnected = false;
/**
* Initialize Redis client for caching.
* Only connects if REDIS_URL is configured and NODE_ENV is production.
*/
export async function initRedisCache(): Promise<void> {
const redisUrl = process.env.REDIS_URL;
const nodeEnv = process.env.NODE_ENV;
if (!redisUrl || nodeEnv !== 'production') {
return;
}
try {
redisClient = createClient({ url: redisUrl });
redisClient.on('error', () => {
isConnected = false;
});
redisClient.on('connect', () => {
isConnected = true;
});
await redisClient.connect();
isConnected = true;
logInfo('redis_connected', {}, config.logLevel);
} catch (error) {
logError(error instanceof Error ? error : new Error(String(error)), { event: 'redis_connection_failed' }, config.logLevel);
redisClient = null;
isConnected = false;
} catch {
redisClient = null;
isConnected = false;
} catch {
redisClient = null;
isConnected = false;
}
}
/**
* Get a value from cache.
* Returns null if key doesn't exist or cache is unavailable.
*/
export async function getCacheValue(key: string): Promise<string | null> {
if (!redisClient || !isConnected) {
return null;
}
try {
return await redisClient.get(key);
} catch (error) {
return null;
}
}
/**
* Set a value in cache with optional TTL (in seconds).
* Returns true if successful, false otherwise.
*/
export async function setCacheValue(
key: string,
value: string,
ttlSeconds?: number,
): Promise<boolean> {
if (!redisClient || !isConnected) {
return false;
}
try {
if (ttlSeconds) {
await redisClient.setEx(key, ttlSeconds, value);
} else {
await redisClient.set(key, value);
}
return true;
} catch (error) {
return false;
}
}
/**
* Delete a value from cache.
* Returns true if key was deleted, false if key didn't exist or error occurred.
*/
export async function deleteCacheValue(key: string): Promise<boolean> {
if (!redisClient || !isConnected) {
return false;
}
try {
const result = await redisClient.del(key);
return result > 0;
} catch (error) {
return false;
}
}
/**
* Clear all cache entries matching a pattern.
* Pattern uses Redis glob syntax (e.g., "campaign:*" matches all campaign keys).
*/
export async function clearCachePattern(pattern: string): Promise<number> {
if (!redisClient || !isConnected) {
return 0;
}
try {
const keys = await redisClient.keys(pattern);
if (keys.length === 0) {
return 0;
}
return await redisClient.del(keys);
} catch (error) {
return 0;
}
}
/**
* Close Redis connection.
*/
export async function closeRedisCache(): Promise<void> {
if (redisClient && isConnected) {
try {
await redisClient.quit();
isConnected = false;
} catch {
isConnected = false;
}
}
}
/**
* Check if cache is available.
*/
export function isCacheAvailable(): boolean {
return isConnected && redisClient !== null;
}
/**
* Get cache statistics (for monitoring).
*/
export async function getCacheStats(): Promise<{
available: boolean;
connected: boolean;
} | null> {
if (!redisClient) {
return null;
}
return {
available: isConnected,
connected: isConnected,
};
}