mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-10-08 04:37:51 +00:00
perf: cache config in memory with write invalidation
This commit is contained in:
parent
db74b427ef
commit
7d3a9c404c
3 changed files with 67 additions and 0 deletions
|
|
@ -2110,3 +2110,4 @@
|
|||
{"type":"task.created","taskId":"task_20260128_Usuv2Y","project":"project-a","status":"todo","id":"evt_aG2Tll254MYY","timestamp":"2026-01-28T18:14:17.785Z"}
|
||||
{"type":"task.created","taskId":"task_20260128_13CrZo","project":"project-b","status":"todo","id":"evt_YNGhKOJL_Tmu","timestamp":"2026-01-28T18:14:17.786Z"}
|
||||
{"type":"task.created","taskId":"task_20260128_RJXi4k","status":"todo","id":"evt_21ZTMT4yYCOp","timestamp":"2026-01-28T18:14:17.799Z"}
|
||||
{"type":"task.status_changed","taskId":"task_20260128_9t1KEa","project":"veritas-kanban","status":"in-progress","previousStatus":"todo","id":"evt_E2py7Rsv0FZs","timestamp":"2026-01-28T18:14:39.641Z"}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,15 @@
|
|||
[
|
||||
{
|
||||
"id": "activity_1769624079642_g7c232tud",
|
||||
"type": "status_changed",
|
||||
"taskId": "task_20260128_9t1KEa",
|
||||
"taskTitle": "SECURITY: Add server-side MIME type validation for attachments",
|
||||
"details": {
|
||||
"from": "todo",
|
||||
"status": "in-progress"
|
||||
},
|
||||
"timestamp": "2026-01-28T18:14:39.642Z"
|
||||
},
|
||||
{
|
||||
"id": "activity_1769623785282_5ct7g0hqu",
|
||||
"type": "comment_added",
|
||||
|
|
|
|||
|
|
@ -201,4 +201,59 @@ describe('ConfigService', () => {
|
|||
expect(results[1]).toEqual(results[2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Cache Behavior', () => {
|
||||
it('should return cached config within TTL', async () => {
|
||||
// First read populates cache
|
||||
const config1 = await service.getConfig();
|
||||
|
||||
// Modify file on disk behind the service's back
|
||||
const raw = JSON.parse(await fs.readFile(configFile, 'utf-8'));
|
||||
raw.defaultAgent = 'amp';
|
||||
// Mark as our own write so the file watcher ignores it,
|
||||
// simulating a read within the TTL window
|
||||
(service as any).lastWriteTime = Date.now();
|
||||
await fs.writeFile(configFile, JSON.stringify(raw, null, 2));
|
||||
|
||||
// Should still return the cached version (TTL hasn't expired)
|
||||
const config2 = await service.getConfig();
|
||||
expect(config2.defaultAgent).toBe(config1.defaultAgent);
|
||||
});
|
||||
|
||||
it('should re-read from disk after invalidateCache()', async () => {
|
||||
const config1 = await service.getConfig();
|
||||
expect(config1.defaultAgent).toBe('claude-code');
|
||||
|
||||
// Modify file on disk
|
||||
const raw = JSON.parse(await fs.readFile(configFile, 'utf-8'));
|
||||
raw.defaultAgent = 'amp';
|
||||
// Suppress watcher for this manual write
|
||||
(service as any).lastWriteTime = Date.now();
|
||||
await fs.writeFile(configFile, JSON.stringify(raw, null, 2));
|
||||
|
||||
// Explicitly invalidate
|
||||
service.invalidateCache();
|
||||
|
||||
const config2 = await service.getConfig();
|
||||
expect(config2.defaultAgent).toBe('amp');
|
||||
});
|
||||
|
||||
it('should update cache on saveConfig without re-reading disk', async () => {
|
||||
const config = await service.getConfig();
|
||||
config.defaultAgent = 'gemini';
|
||||
await service.saveConfig(config);
|
||||
|
||||
// Should return updated value from cache, not disk
|
||||
const config2 = await service.getConfig();
|
||||
expect(config2.defaultAgent).toBe('gemini');
|
||||
});
|
||||
|
||||
it('should clean up watcher on dispose()', async () => {
|
||||
await service.getConfig(); // triggers watcher setup
|
||||
service.dispose();
|
||||
// After dispose, cache should be cleared
|
||||
expect((service as any).config).toBeNull();
|
||||
expect((service as any).watcher).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue