♻️ cli: buffering reindexing of documents

This commit is contained in:
Eric Doughty-Papassideris
2024-04-23 14:45:50 +02:00
committed by ericlinagora
parent 3e2adf9c1c
commit 5766d2684b
2 changed files with 47 additions and 1 deletions
@@ -13,6 +13,7 @@ import iterateOverRepoPages from "../../../utils/iterate-over-repository-pages";
import BaseReindexer from "./base-reindexer";
import type ReindexerOptions from "./reindexer-options";
import BufferedAction from "../../../utils/buffered-action";
export default class DocumentsReindexer extends BaseReindexer<DriveFile> {
constructor(platform: TdrivePlatform, options: ReindexerOptions) {
@@ -62,6 +63,7 @@ export default class DocumentsReindexer extends BaseReindexer<DriveFile> {
const repository = await this.dbRepository();
let count = 0,
countChanged = 0;
const bufferedWriter = new BufferedAction<DriveFile>(100, items => repository.saveAll(items));
await iterateOverRepoPages(
repository,
async entities => {
@@ -99,12 +101,13 @@ export default class DocumentsReindexer extends BaseReindexer<DriveFile> {
);
if (content_keywords !== entity.content_keywords) {
entity.content_keywords = content_keywords;
repository.save(entity);
bufferedWriter.do(entity);
countChanged++;
}
} catch (err) {
this.statusFail(err.stack);
}
bufferedWriter.flush();
}
this.statusStart(`Repaired ${count} documents (${countChanged} changed)`);
},
@@ -0,0 +1,43 @@
/** Batch operations on objects into groups of `minimumBatchSize`
* provided to the constructor's callback.
*
* Call `do` or `doAll` to enqueue items, don't forget to:
* - call flush after all items are enqueued
* - await all the methods (do* and flush)
*
* The callback can be called with more than `minimumBatchSize`
* when `doAll` is used - see note on that method.
*/
export default class BufferedAction<T> {
// TODO: low and high marks
private buffer: T[] = [];
constructor(
private readonly minimumBatchSize: number,
private readonly action: (items: T[]) => Promise<void>,
) {}
/** Call to empty all items by calling the callback with all items if at least one is queued */
public async flush() {
const buffer = this.buffer;
if (!buffer.length) return 0;
this.buffer = new Array(this.minimumBatchSize);
this.action(buffer);
return buffer.length;
}
private async flushIfShould() {
return this.buffer.length >= this.minimumBatchSize ? await this.flush() : 0;
}
/** Enqueue a single item to process in the batch later. Returns items actually processed. */
public async do(item: T) {
this.buffer.push(item);
return await this.flushIfShould();
}
/** Enqueue an array of items to process in the batch later.
* If the additional items goes beyond `minimumBatchSize`,
* all items will be flushed at once, however many was added
* by `doAll`.
* Returns items actually processed. */
public async doAll(items: T[]) {
this.buffer = this.buffer.concat(items);
return await this.flushIfShould();
}
}