Skip to content

fix(server): sync PostgreSQL and LanceDB discrepancies on startup - #553

Merged
hmjn023 merged 1 commit into
developfrom
fix/lancedb-postgres-startup-sync
Jun 28, 2026
Merged

fix(server): sync PostgreSQL and LanceDB discrepancies on startup#553
hmjn023 merged 1 commit into
developfrom
fix/lancedb-postgres-startup-sync

Conversation

@hmjn023

@hmjn023 hmjn023 commented Jun 28, 2026

Copy link
Copy Markdown
Owner

概要

サーバー起動時に PostgreSQL と LanceDB のメディアデータの不整合を検出し、差分同期ジョブを実行する機能を追加します。

変更内容

  • ILanceDbDumpServicereadMediaIds 関数を追加し、LanceDB に格納されているメディアID一覧を取得できるように変更
  • MaintenanceService のスタートアップ処理にて、LanceDB の manifest ファイルが存在する場合に PostgreSQL 内のメディアIDと LanceDB 内のメディアIDを比較する処理を追加
  • 差分(不整合)を検出した場合、BackupService.queueSourceLanceDBDelta を呼んで差分データをキューし、差分同期ジョブ(sync_lancedb_delta)を生成する処理を実装
  • 起動時チェックにおける不整合検出処理のユニットテストを追加

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the startup maintenance checks by comparing media IDs between PostgreSQL and LanceDB to queue delta syncs for any discrepancies, rather than defaulting to a full sync. The review feedback identifies two critical improvement opportunities: chunking the discrepancy lists when queueing delta syncs to avoid exceeding PostgreSQL parameter limits, and paginating the LanceDB query when reading media IDs to prevent potential Out-of-Memory (OOM) errors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +143 to +158
if (toUpsert.length > 0) {
await BackupService.queueSourceLanceDBDelta(
source.id,
toUpsert,
"upsert",
{ enqueueJob: false },
);
}
if (toDelete.length > 0) {
await BackupService.queueSourceLanceDBDelta(
source.id,
toDelete,
"delete",
{ enqueueJob: false },
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

PostgreSQLのプレースホルダー(パラメータ)数の上限(65,535)やメモリ負荷を考慮すると、toUpserttoDelete の件数が非常に大きい場合に BackupService.queueSourceLanceDBDelta 内のバルクインサート処理でエラーが発生する可能性があります。

lanceDbSyncDirty テーブルは4カラム(mediaSourceId, mediaId, operation, updatedAt)を持つため、一度にインサートできる件数は最大でも約16,000件程度に制限されます。

安全のため、toUpsert および toDelete を一定のチャンクサイズ(例: 1000件ずつ)に分割して queueSourceLanceDBDelta を呼び出すように修正することを推奨します。

							const CHUNK_SIZE = 1000;
							if (toUpsert.length > 0) {
								for (let i = 0; i < toUpsert.length; i += CHUNK_SIZE) {
									const chunk = toUpsert.slice(i, i + CHUNK_SIZE);
									await BackupService.queueSourceLanceDBDelta(
										source.id,
										chunk,
										"upsert",
										{ enqueueJob: false },
									);
								}
							}
							if (toDelete.length > 0) {
								for (let i = 0; i < toDelete.length; i += CHUNK_SIZE) {
									const chunk = toDelete.slice(i, i + CHUNK_SIZE);
									await BackupService.queueSourceLanceDBDelta(
										source.id,
										chunk,
										"delete",
										{ enqueueJob: false },
									);
								}
							}

Comment on lines +848 to +857
async function readMediaIds(lanceDbDir: string): Promise<string[]> {
const connect = await getConnect();
const db = await connect(lanceDbDir);
const mediaTable = await db.openTable("media");
const rows = await mediaTable.query().select(["id"]).toArray();
return rows.flatMap((row) => {
const id = safeString(row.id);
return id ? [id] : [];
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

mediaTable.query().select(["id"]).toArray() は、LanceDBの media テーブルに格納されているすべてのレコードのIDを一度にメモリ上に読み込みます。

メディアの件数が非常に多い場合(数十万〜数百万件など)、一時的に大量のメモリを消費し、最悪の場合Out-of-Memory (OOM) エラーを引き起こす可能性があります。

すでに定義されている readPage などのヘルパー関数と同様に、一定のチャンクサイズ(例: 5000件ずつ)で分割してIDを取得し、配列に結合していく方式にすることで、メモリ消費を抑え安全に処理することができます。

	async function readMediaIds(lanceDbDir: string): Promise<string[]> {
		const connect = await getConnect();
		const db = await connect(lanceDbDir);
		const mediaTable = await db.openTable("media");
		const allIds: string[] = [];
		let offset = 0;
		const limit = 5000;
		while (true) {
			const rows = await mediaTable.query().select(["id"]).limit(limit).offset(offset).toArray();
			if (rows.length === 0) break;
			for (const row of rows) {
				const id = safeString(row.id);
				if (id) {
					allIds.push(id);
				}
			}
			if (rows.length < limit) break;
			offset += rows.length;
		}
		return allIds;
	}
References
  1. When implementing chunked or streaming reads of relational data from a database (such as LanceDB) to prevent Out-of-Memory (OOM) errors, avoid loading all tables entirely into memory.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4fb7927a-59f4-4b61-9b53-420277b54504

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@hmjn023
hmjn023 merged commit b98726a into develop Jun 28, 2026
1 check passed
@hmjn023
hmjn023 deleted the fix/lancedb-postgres-startup-sync branch June 28, 2026 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant