Skip to content

Commit 7b537d2

Browse files
committed
Sort out how we will expose issues reading the cache - important in future if we update the format
1 parent 7bed403 commit 7b537d2

File tree

6 files changed

+99
-31
lines changed

6 files changed

+99
-31
lines changed

src/dependencies.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import {Logger} from 'pino';
22
import {Failure, Email, DomainEvent, ResourceVersion} from './types';
33
import * as TE from 'fp-ts/TaskEither';
4+
import * as t from 'io-ts';
45
import {FailureWithStatus} from './types/failure-with-status';
56
import {StatusCodes} from 'http-status-codes';
67

78
import {Resource} from './types/resource';
89
import {EventName, EventOfType} from './types/domain-event';
910
import {SharedReadModel} from './read-models/shared-state';
1011

12+
type TrainingSheetId = string;
13+
1114
export type Dependencies = {
1215
commitEvent: (
1316
resource: Resource,
@@ -38,14 +41,22 @@ export type Dependencies = {
3841
sendEmail: (email: Email) => TE.TaskEither<Failure, string>;
3942
getCachedSheetData: () => TE.TaskEither<
4043
FailureWithStatus,
41-
ReadonlyArray<
42-
| EventOfType<'EquipmentTrainingQuizResult'>
43-
| EventOfType<'EquipmentTrainingQuizSync'>
44-
>
44+
ReadonlyArray<{
45+
cache_entry_id: string;
46+
cached_timestamp: Date;
47+
sheet_id: string;
48+
equipment_id: string;
49+
cached_data: t.Validation<
50+
ReadonlyArray<
51+
| EventOfType<'EquipmentTrainingQuizResult'>
52+
| EventOfType<'EquipmentTrainingQuizSync'>
53+
>
54+
>;
55+
}>
4556
>;
4657
cacheSheetData: (
4758
cacheTimestamp: Date,
48-
sheetId: string,
59+
sheetId: TrainingSheetId,
4960
data: ReadonlyArray<
5061
| EventOfType<'EquipmentTrainingQuizSync'>
5162
| EventOfType<'EquipmentTrainingQuizResult'>

src/index.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import {createTerminus} from '@godaddy/terminus';
1313
import http from 'http';
1414
import {pipe} from 'fp-ts/lib/function';
1515
import * as TE from 'fp-ts/TaskEither';
16-
import * as E from 'fp-ts/Either';
1716
import {ensureEventTableExists} from './init-dependencies/event-store/ensure-events-table-exists';
1817
import {initDependencies} from './init-dependencies';
1918
import * as libsqlClient from '@libsql/client';
2019
import cookieSession from 'cookie-session';
2120
import {initRoutes} from './routes';
2221
import {ensureCachedSheetDataTableExists} from './init-dependencies/google/ensure-cached-sheet-data-table-exists';
22+
import {loadCachedSheetData} from './load-cached-sheet-data';
2323

2424
// Dependencies and Config
2525
const conf = loadConfig();
@@ -95,21 +95,12 @@ void (async () => {
9595
)();
9696

9797
deps.logger.info('Loading cached external events...');
98-
const events = await deps.getCachedSheetData()();
99-
if (E.isLeft(events)) {
100-
// Potential pitfall here - transient db errors could produce large spikes in processing.
101-
// Tradeoff is that an error/bug in cached sheet data doesn't bring down the application.
102-
deps.logger.error(
103-
events.left,
104-
'Failed to load cached external events data - continuing anyway...'
105-
);
106-
} else {
107-
deps.logger.info(
108-
'Loaded %s events from external events data cache',
109-
events.right.length
110-
);
111-
events.right.forEach(deps.sharedReadModel.updateState);
112-
}
98+
await loadCachedSheetData(
99+
deps.getCachedSheetData,
100+
deps.logger,
101+
deps.sharedReadModel.updateState
102+
);
103+
deps.logger.info('Cached external events loaded');
113104
await deps.sharedReadModel.asyncRefresh()();
114105
await deps.sharedReadModel.asyncApplyExternalEventSources()();
115106

src/init-dependencies/google/get-cached-sheet-data.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ export const getCachedSheetData =
6060
TE.map(table =>
6161
pipe(
6262
table.rows,
63-
RA.map(entry => ({
64-
...entry,
65-
cached_data: extractCachedEvents(entry.cached_data),
63+
RA.map(row => ({
64+
...row,
65+
cached_data: extractCachedEvents(row.cached_data),
6666
}))
6767
)
6868
)

src/load-cached-sheet-data.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {Logger} from 'pino';
2+
import * as E from 'fp-ts/Either';
3+
import {Dependencies} from './dependencies';
4+
import {SharedReadModel} from './read-models/shared-state';
5+
6+
export const loadCachedSheetData = async (
7+
getCachedSheetData: Dependencies['getCachedSheetData'],
8+
logger: Logger,
9+
updateState: SharedReadModel['updateState']
10+
) => {
11+
const events = await getCachedSheetData()();
12+
if (E.isLeft(events)) {
13+
// Potential pitfall here - transient db errors could produce large spikes in processing.
14+
// Tradeoff is that an error/bug in cached sheet data doesn't bring down the application.
15+
logger.error(
16+
events.left,
17+
'Failed to load any cached external events data - continuing anyway...'
18+
);
19+
} else {
20+
logger.info(
21+
'Loaded events for %s pieces of equipment from external events data cache',
22+
events.right.length
23+
);
24+
events.right.forEach(cachedSheetData => {
25+
if (E.isLeft(cachedSheetData.cached_data)) {
26+
logger.info(
27+
'Failed to load events for sheet %s, equipment %s generated at %s, skipping...',
28+
cachedSheetData.sheet_id,
29+
cachedSheetData.equipment_id,
30+
cachedSheetData.cached_timestamp.toISOString()
31+
);
32+
} else {
33+
logger.info(
34+
'Loaded % events for sheet %s, equipment %s generated at %s',
35+
cachedSheetData.cached_data.right.length,
36+
cachedSheetData.sheet_id,
37+
cachedSheetData.equipment_id,
38+
cachedSheetData.cached_timestamp.toISOString()
39+
);
40+
cachedSheetData.cached_data.right.forEach(updateState);
41+
}
42+
});
43+
}
44+
};

tests/read-models/test-framework.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {Dependencies} from '../../src/dependencies';
1919
import {applyToResource} from '../../src/commands/apply-command-to-resource';
2020
import {initSharedReadModel} from '../../src/read-models/shared-state';
2121
import {localGoogleHelpers} from '../init-dependencies/pull-local-google';
22+
import {cacheSheetData} from '../../src/init-dependencies/google/get-cached-sheet-data';
23+
import {ensureCachedSheetDataTableExists} from '../../src/init-dependencies/google/ensure-cached-sheet-data-table-exists';
2224

2325
type ToFrameworkCommands<T> = {
2426
[K in keyof T]: {
@@ -58,14 +60,16 @@ export const initTestFramework = async (
5860
dbClient,
5961
logger,
6062
O.some(localGoogleHelpers),
61-
googleRateLimitMs
63+
googleRateLimitMs,
64+
cacheSheetData(dbClient)
6265
);
6366
const frameworkCommitEvent = commitEvent(
6467
dbClient,
6568
logger,
6669
sharedReadModel.asyncRefresh
6770
);
6871
await ensureEventTableExists(dbClient)();
72+
await ensureCachedSheetDataTableExists(dbClient)();
6973
const frameworkGetAllEvents = () =>
7074
pipe(getAllEvents(dbClient)(), T.map(getRightOrFail))();
7175
const frameworkGetAllEventsByType = <EN extends EventName>(eventType: EN) =>

tests/training-sheets/cached-sheet-data.test.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
getCachedSheetData,
66
} from '../../src/init-dependencies/google/get-cached-sheet-data';
77
import {UUID} from 'io-ts-types';
8+
import * as t from 'io-ts';
89
import {faker} from '@faker-js/faker';
910
import {constructEvent, EventOfType} from '../../src/types/domain-event';
1011
import {getRightOrFail} from '../helpers';
@@ -14,14 +15,23 @@ describe('Cache sheet data', () => {
1415
describe('Cache then restore', () => {
1516
const equipmentId = '326e8fda-7be8-4cd8-87d5-7cdfafebf996' as UUID;
1617
const sheetId = 'myTestingSheetId';
17-
let cachedData: ReadonlyArray<
18-
| EventOfType<'EquipmentTrainingQuizResult'>
19-
| EventOfType<'EquipmentTrainingQuizSync'>
20-
>;
18+
const cacheTimestamp = new Date(2024, 1, 23, 4, 23, 45);
19+
let cachedData: ReadonlyArray<{
20+
cache_entry_id: string;
21+
cached_timestamp: Date;
22+
sheet_id: string;
23+
equipment_id: string;
24+
cached_data: t.Validation<
25+
ReadonlyArray<
26+
| EventOfType<'EquipmentTrainingQuizResult'>
27+
| EventOfType<'EquipmentTrainingQuizSync'>
28+
>
29+
>;
30+
}>;
2131
beforeEach(async () => {
2232
const db = libsqlClient.createClient({url: ':memory:'});
2333
await ensureCachedSheetDataTableExists(db)();
24-
await cacheSheetData(db)(new Date(2024, 1, 23, 4, 23, 45), sheetId, [
34+
await cacheSheetData(db)(cacheTimestamp, sheetId, [
2535
constructEvent('EquipmentTrainingQuizSync')({
2636
equipmentId,
2737
}),
@@ -39,8 +49,16 @@ describe('Cache sheet data', () => {
3949
])();
4050
cachedData = getRightOrFail(await getCachedSheetData(db)()());
4151
});
52+
it('Each sheet is cached', () => {
53+
expect(cachedData).toHaveLength(1); // 1 sheet
54+
});
4255
it('All events cached are returned', () => {
43-
expect(cachedData).toHaveLength(2);
56+
expect(getRightOrFail(cachedData[0].cached_data)).toHaveLength(2); // 2 events.
57+
});
58+
it('Event cache is correctly labeled', () => {
59+
expect(cachedData[0].equipment_id).toStrictEqual(equipmentId);
60+
expect(cachedData[0].sheet_id).toStrictEqual(sheetId);
61+
expect(cachedData[0].cached_timestamp).toStrictEqual(cacheTimestamp);
4462
});
4563
});
4664
});

0 commit comments

Comments
 (0)