Skip to content

Commit dcf8977

Browse files
authored
log-server: fix batch log's date (#155)
1 parent 566b83a commit dcf8977

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

.changeset/late-emus-fold.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@lightmill/log-server': major
3+
---
4+
5+
Fix bach log's date and ordering. Requires db migration.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Kysely } from 'kysely';
2+
3+
export async function up(
4+
db: Kysely<{ log: { clientDate: Date; createdAt?: Date } }>
5+
) {
6+
await db.transaction().execute(async (trx) => {
7+
await trx.schema
8+
.alterTable('log')
9+
.addColumn('batchOrder', 'integer')
10+
.execute();
11+
12+
await trx.schema.dropIndex('logSort').execute();
13+
14+
await trx.schema
15+
.createIndex('logSort')
16+
.on('log')
17+
.columns([
18+
'experimentId',
19+
'runId',
20+
'type',
21+
'clientDate',
22+
'createdAt',
23+
'batchOrder',
24+
])
25+
.execute();
26+
});
27+
}
28+
29+
export async function down(db: Kysely<unknown>) {
30+
await db.transaction().execute(async (trx) => {
31+
await trx.schema.dropIndex('logSort').execute();
32+
await trx.schema.alterTable('log').dropColumn('batchOrder').execute();
33+
// Put back the old index.
34+
await trx.schema
35+
.createIndex('logSort')
36+
.on('log')
37+
.columns([
38+
'experimentId',
39+
'runId',
40+
'type',
41+
'clientDate',
42+
'createdAt',
43+
'logId',
44+
])
45+
.execute();
46+
});
47+
}

packages/log-server/src/store.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
import { JsonObject } from 'type-fest';
1515
import loglevel, { LogLevelDesc } from 'loglevel';
1616
import { arrayify } from './utils.js';
17-
import { groupBy } from 'remeda';
17+
import { pipe, sortBy } from 'remeda';
1818

1919
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
2020
const migrationFolder = path.join(__dirname, 'db-migrations');
@@ -32,6 +32,9 @@ type LogTable = {
3232
type: string;
3333
createdAt: string;
3434
clientDate?: string;
35+
// batchOrder records the order in which the logs were sent by the client
36+
// in a single request. This is used to sort logs with the same clientDate.
37+
batchOrder?: number;
3538
};
3639
type LogValueTable = {
3740
logId: bigint;
@@ -127,34 +130,33 @@ export class Store {
127130
) {
128131
await this.#db.transaction().execute(async (trx) => {
129132
let createdAt = new Date().toISOString();
130-
let dbLogGroups = groupBy(
133+
let dbLogs = pipe(
131134
await trx
132135
.insertInto('log')
133136
.values(
134-
logs.map(({ type, date }) => {
137+
logs.map(({ type, date }, i) => {
135138
return {
136139
type,
137140
runId,
138141
experimentId,
139142
createdAt,
140143
clientDate: date.toISOString(),
144+
batchOrder: i,
141145
};
142146
})
143147
)
144-
.returning(['logId', 'type'])
148+
.returning(['logId', 'batchOrder'])
145149
.execute(),
146-
(log) => log.type
150+
sortBy((log) => log.batchOrder ?? 0)
147151
);
148152

149153
// Bulk insert returning values does not guarantee order, so we need to
150154
// match the log values logs to returned log ids.
151155
let dbValues = [];
152156
for (let log of logs) {
153-
let dbLog = dbLogGroups[log.type].pop();
157+
let dbLog = dbLogs.shift();
154158
if (dbLog == null) {
155-
throw new Error(
156-
`failed to find an unassigned inserted log with type "${log.type}"`
157-
);
159+
throw new Error(`could not insert log values: log was not inserted`);
158160
}
159161
dbValues.push(...deconstructValues(log.values, { logId: dbLog.logId }));
160162
}
@@ -205,7 +207,7 @@ export class Store {
205207
.orderBy('log.type')
206208
.orderBy('log.clientDate')
207209
.orderBy('log.createdAt')
208-
.orderBy('log.logId')
210+
.orderBy('log.batchOrder')
209211
.select([
210212
'log.experimentId as experimentId',
211213
'log.runId as runId',

0 commit comments

Comments
 (0)