Skip to content

fix: resolve memory crash on large image imports by adding thumbnails and bounded concurrency#109

Merged
amemya merged 6 commits into
mainfrom
fix/large-import-crash
Jun 23, 2026
Merged

fix: resolve memory crash on large image imports by adding thumbnails and bounded concurrency#109
amemya merged 6 commits into
mainfrom
fix/large-import-crash

Conversation

@amemya

@amemya amemya commented Jun 22, 2026

Copy link
Copy Markdown
Owner

resolved #108

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f5cad33c-6d6d-4105-ae98-712521efa38d

📥 Commits

Reviewing files that changed from the base of the PR and between c78fcd8 and 2dc0e43.

📒 Files selected for processing (1)
  • handler.go

📝 Walkthrough

Summary by CodeRabbit

リリースノート

  • 新機能

    • サムネイル表示機能を追加しました。フロントエンドでサムネイル画像を優先的に表示するようになります
    • 大量の画像アップロード時に上限達成を通知するようになりました
  • 改善

    • エラーメッセージの表示タイミングを改善しました

Walkthrough

フィルムストリップで高解像度画像を直接読み込むことによるメモリクラッシュを解消するため、Go バックエンドに /api/thumb エンドポイントを新設し、EXIF サムネイル抽出またはリサイズ生成でサムネイルを返す。あわせてトークン上限定数化・同時処理セマフォ・2000件パス制限を追加し、フロントエンドは thumbURL を優先してサムネイルを表示する。

Changes

サムネイルAPI追加とメモリクラッシュ対策

Layer / File(s) Summary
型定義・定数・インポートの追加
frontend/src/types.ts, app.go, handler.go
ImportedImageExifResult(TS/Go 両方)に thumbURL プロパティを追加。handler.gomaxImageTokens 定数、fileOpenSemthumbProcessSem セマフォ、image/image/jpeg インポートを追加。
handleThumb エンドポイント実装とルーティング
handler.go
Middleware/api/thumb ルートを追加し handleThumb へ委譲。handleThumb は EXIF サムネイル抽出 → 失敗時に最大 256×256 リサイズ JPEG 生成のフォールバックをセマフォ制御下で実行。handleImage にも fileOpenSem を適用し、registerImageToken 上限を maxImageTokens に置き換え。
app.go: thumbUrl 生成・2000件パス制限
app.go
ProcessPaths で有効パスが 2000 件超の場合に先頭 2000 件へ切り詰めてエラー ExifResult を追加。画像URL生成で handler 有効時は /api/thumb トークン URL を ThumbURL として生成し、無効時は ImageURL にフォールバック。ExifResult 構築に ThumbURL フィールドを追加。
フロントエンド: thumbURL 表示とエラーハンドリング変更
frontend/src/App.tsx, frontend/src/hooks/useImageManager.ts
フィルムストリップの img srcimg.thumbURL || img.imageURL に変更。handleExifResults でエラー検出・showToast 呼び出しを validResults の件数にかかわらず先行実行し、件数が 0 の場合のみ早期 return するよう制御順序を変更。

Sequence Diagram(s)

sequenceDiagram
  rect rgba(173, 216, 230, 0.5)
    note over Frontend,app.go: 画像インポートフロー
    Frontend->>app.go: ProcessPaths (ファイルパス群)
    app.go->>app.go: 有効パス > 2000 件 → 先頭2000件に切り詰め + エラーExifResult追加
    app.go->>handler.go: registerImageToken (imageToken, thumbToken)
    app.go-->>Frontend: ExifResult { imageURL, thumbURL }
  end
  rect rgba(144, 238, 144, 0.5)
    note over Frontend,handler.go: サムネイル表示フロー
    Frontend->>handler.go: GET /api/thumb?token=xxx
    handler.go->>handler.go: fileOpenSem 取得
    handler.go->>handler.go: EXIF JpegThumbnail 試行
    alt EXIF サムネイルあり
      handler.go-->>Frontend: image/jpeg (EXIF 埋め込みサムネイル)
    else EXIF なし / サイズ不足
      handler.go->>handler.go: thumbProcessSem 取得 → デコード → 256px リサイズ
      handler.go-->>Frontend: image/jpeg (リサイズ済みサムネイル)
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50分

Possibly related PRs

  • amemya/ExifFrame#41: handler.goregisterImageToken/画像トークンキャッシュと app.goExifResult.ImageURL およびハンドラ未初期化時フォールバック部分に直接重複する変更がある。
  • amemya/ExifFrame#70: 両 PR が app.goProcessPaths を修正しており、一方は2000件上限とエラー ExifResult 挿入、他方は並列ワーカーと結果収集の整理と、同一関数への変更が重なる。
  • amemya/ExifFrame#74: 本 PR の frontend/src/hooks/useImageManager.tshandleExifResults エラー・トースト処理変更が、同 PR の useImageManager リファクタリングと直接重複している。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR タイトルは「fix: resolve memory crash on large image imports by adding thumbnails and bounded concurrency」で、大量画像インポート時のメモリクラッシュ問題をサムネイル機能と並列制御で解決する主要な変更を明確に示しており、変更セットの主要な目的を適切に要約しています。
Description check ✅ Passed PR説明は「resolved #108」とシンプルですが、リンク先の issue #108 を参照することで変更の意図が明確に関連付けられており、リンクによる説明は変更セットと関連があります。
Linked Issues check ✅ Passed PR の変更内容は issue #108 の全ての主要な目的を満たしています: (1) サムネイル専用 API エンドポイント /api/thumb の追加、(2) EXIF サムネイル抽出ロジックの実装、(3) フォールバックとして最大 256px の軽量 JPEG 生成、(4) サムネイル生成の並列制限(セマフォ)による OOM 防止、(5) トークン上限の定数化(maxImageTokens = 500 または 2000)、(6) フロントエンド側での thumbURL の統合とフィルムストリップ表示の最適化。
Out of Scope Changes check ✅ Passed 全ての変更が issue #108 で定義されたサムネイル機能、並列制限、トークン上限の定数化というスコープ内に収まっており、無関係な変更は含まれていません。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/large-import-crash

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app.go`:
- Around line 214-218: The hardcoded limit value of 2000 in the validPaths
length check is not unified with the maxImageTokens constant defined elsewhere,
leading to duplicate management of the same threshold. Extract the 2000 value
into a single shared constant definition that can be referenced in both the
len(validPaths) comparison and the maxImageTokens definition. This ensures the
image import limit and token holding limit remain synchronized and prevents
future misalignment when either limit needs to be updated.

In `@handler.go`:
- Around line 160-163: The error return values from w.Write(pic) and
jpeg.Encode(...) calls in the image response handler are not being checked,
making it impossible to detect connection failures or write errors. Check the
error return value from both w.Write(pic) and the jpeg.Encode(...) call wherever
they appear in handler.go (including the instances around line 160 and line
202), and handle any errors appropriately by logging them or writing an error
response to the client. Do not silently ignore these errors as they make it
difficult to diagnose failures in production.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: df38719a-70c8-4425-ba8b-80bbfb0eee59

📥 Commits

Reviewing files that changed from the base of the PR and between 92e4607 and b21e95b.

📒 Files selected for processing (5)
  • app.go
  • frontend/src/App.tsx
  • frontend/src/hooks/useImageManager.ts
  • frontend/src/types.ts
  • handler.go

Comment thread app.go Outdated
Comment thread handler.go

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@handler.go`:
- Line 221: The w.Write(buf.Bytes()) call on line 221 does not check or log
errors from the write operation, whereas similar error handling is performed for
EXIF thumbnail writes in the earlier section (lines 162-164). Although HTTP
errors cannot be returned after headers are already sent, you should capture the
error returned by w.Write and add logging to record any write failures for
debugging purposes, following the same pattern used in the EXIF thumbnail error
handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 272c316d-1f75-4ec5-a935-57fa65aaac3d

📥 Commits

Reviewing files that changed from the base of the PR and between b21e95b and c78fcd8.

📒 Files selected for processing (2)
  • app.go
  • handler.go

Comment thread handler.go
}

w.Header().Set("Content-Type", "image/jpeg")
w.Write(buf.Bytes())

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

w.Write のエラーを検査してログ出力してください。

Line 162-164 では EXIF サムネイル書き込み時にエラーをログ出力していますが、こちらでは未処理です。ヘッダー送信後なので HTTP エラーは返せませんが、デバッグのためにログ出力を追加してください。

🔧 修正案
 	w.Header().Set("Content-Type", "image/jpeg")
-	w.Write(buf.Bytes())
+	if _, err := w.Write(buf.Bytes()); err != nil {
+		log.Printf("Failed to write generated thumbnail: %v", err)
+	}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
w.Write(buf.Bytes())
w.Header().Set("Content-Type", "image/jpeg")
if _, err := w.Write(buf.Bytes()); err != nil {
log.Printf("Failed to write generated thumbnail: %v", err)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@handler.go` at line 221, The w.Write(buf.Bytes()) call on line 221 does not
check or log errors from the write operation, whereas similar error handling is
performed for EXIF thumbnail writes in the earlier section (lines 162-164).
Although HTTP errors cannot be returned after headers are already sent, you
should capture the error returned by w.Write and add logging to record any write
failures for debugging purposes, following the same pattern used in the EXIF
thumbnail error handling.

@amemya

amemya commented Jun 23, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@amemya amemya merged commit 8741b83 into main Jun 23, 2026
4 checks passed
@amemya amemya deleted the fix/large-import-crash branch June 23, 2026 01:46
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.

画像100枚読み込み時のクラッシュ

1 participant