Skip to content

fix: reduce worker memory for large Garmin dump imports - #1635

Merged
Asherlc merged 4 commits into
mainfrom
Asherlc/kinshasa-v1
Jul 15, 2026
Merged

Asherlc merged 4 commits into
mainfrom
Asherlc/kinshasa-v1

Conversation

@Asherlc

@Asherlc Asherlc commented Jul 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fix worker OOM when importing large Garmin dumps (15K+ FIT files).

Three root causes for memory consumption:

  1. activitySummary.raw embedded the entire Garmin summary object via .passthrough() for every FIT file job entry — hundreds of MB for large dumps
  2. Single FlowProducer.add() built all 15K+ child jobs in one .map() then serialized the entire tree to JSON at once
  3. parsedDump data (summaries, fitFiles) stayed in memory after building fitJobEntries but before flow creation

Changes

  • src/providers/garmin-dump.ts: Drop raw from garminSummaryToFitJobSummary; release parsedDump arrays after building fitJobEntries
  • src/jobs/garmin-dump-flow.ts: Batch FlowProducer.add() into chunks of 500 (FLOW_BATCH_SIZE), each with a unique batch job ID via createBatchId
  • src/jobs/process-garmin-dump-import-job.ts: Persist batchIds array in checkpoint; aggregate results/failures across multiple batch children
  • src/jobs/queues.ts: Make raw optional in fitFileImportActivitySummarySchema
  • Tests: Updated flow and import-job tests to cover multi-batch behavior and batch ID uniqueness

Summary by cubic

Prevents worker OOM when importing large Garmin dumps (15K+ FIT files) by batching flow creation, trimming job payloads, and letting parsed dump memory be collected sooner. Also handles zero-file imports and merges partial batch failures into the final result.

  • Bug Fixes

    • Batch FlowProducer.add() into chunks of 500 via FLOW_BATCH_SIZE, with unique batch IDs from createBatchId.
    • Persist batchIds and aggregate results across batches; always append partial batch failures to errors.
    • Guard missing-batch-result errors when totalFitFiles is 0; improve waiting logs to include batch count.
    • Drop raw Garmin summary payloads from job entries; make fitFileImportActivitySummarySchema.raw optional.
    • Avoid retaining parsedDump by spread-copying tempDirectories into the prepared import so parsed data is GC’d before batch flows run.
    • Tests cover multi-batch flows, batch ID uniqueness, zero-file imports, and partial failure merging.
  • Migration

    • If you read activitySummary.raw, handle it being absent (now optional).

Written for commit 4d7448b. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Large Garmin FIT imports are now processed in batches of up to 500 files, with deterministic per-batch job tracking.
    • Import results aggregate records synced and errors across all batches, including per-batch failure reporting.
  • Bug Fixes
    • Improved handling for large imports to prevent identifier collisions and ensure complete result aggregation.
    • When there are no FIT files to process, the import now finalizes correctly.
    • Activity summaries no longer include unnecessary raw data; activity summaries may omit raw details when unavailable.

Batch FlowProducer.add() calls into chunks of 500 instead of
serializing all children in one tree, drop raw Garmin summary
payloads from job entries, and release parsed dump data before
flow creation. Prevents OOM on dumps with 15K+ FIT files.
Copilot AI review requested due to automatic review settings July 15, 2026 19:49
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@sourcery-ai sourcery-ai 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.

Sorry @Asherlc, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Asherlc has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours. Upgrade to a paid plan for unlimited reviews.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e4079138-d58b-4350-8915-2bd3b2e257f9

📥 Commits

Reviewing files that changed from the base of the PR and between d8360ff and 4d7448b.

📒 Files selected for processing (6)
  • src/jobs/garmin-dump-flow.test.ts
  • src/jobs/garmin-dump-flow.ts
  • src/jobs/process-garmin-dump-import-job.test.ts
  • src/jobs/process-garmin-dump-import-job.ts
  • src/jobs/queues.ts
  • src/providers/garmin-dump.ts

📝 Walkthrough

Walkthrough

Garmin FIT imports are split into 500-entry batch flows with deterministic IDs. Checkpoints track and aggregate results across batches, while generated activity-summary data omits the raw Garmin summary.

Changes

Garmin FIT batching

Layer / File(s) Summary
Batch flow creation
src/jobs/garmin-dump-flow.ts, src/jobs/garmin-dump-flow.test.ts
FIT entries are split into 500-entry flows with deterministic batch IDs, batch-scoped children, and uniqueness/count assertions.
Checkpoint batch aggregation
src/jobs/process-garmin-dump-import-job.ts, src/jobs/process-garmin-dump-import-job.test.ts
Checkpoints store batch IDs and aggregate records, errors, and failures across matching child batches, including zero-file and partial-failure cases.
Activity summary payload handling
src/jobs/queues.ts, src/providers/garmin-dump.ts
Raw activity summaries become optional and are omitted from generated job data; temporary-directory data is copied during preparation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GarminDump
  participant ImportJob
  participant BatchFlows
  participant ChildJobs
  GarminDump->>ImportJob: prepare FIT job entries
  ImportJob->>BatchFlows: enqueue 500-entry batch flows
  BatchFlows->>ChildJobs: create FIT and extraction jobs
  ChildJobs-->>ImportJob: return results and failures
  ImportJob->>ImportJob: aggregate results by batch ID
Loading

Possibly related issues

Possibly related PRs

  • Asherlc/dofek#1599 — Implements related Garmin dump fan-out flows and batch-parent result aggregation.

Suggested labels: area/providers, type/bug

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is relevant and imperative, but it omits the required area prefix for a backend worker change. Rename it to include an area prefix, e.g. "[jobs] reduce worker memory for large Garmin dump imports".
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

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 `@src/jobs/process-garmin-dump-import-job.ts`:
- Around line 190-198: Update the batch result handling around
batchFailureFromChildren and fitResult: allow a zero-file import (batchIds
empty) to produce the existing zero-record result without throwing, while still
throwing for a missing result when batches were expected and no failures exist.
Always merge batchFailures into the final fitResult.errors, including when
batchResult contains successful partial results, preserving all existing result
data and failure messages.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d441388f-f155-4576-a036-161e92c972b9

📥 Commits

Reviewing files that changed from the base of the PR and between d8360ff and 650cc95.

📒 Files selected for processing (6)
  • src/jobs/garmin-dump-flow.test.ts
  • src/jobs/garmin-dump-flow.ts
  • src/jobs/process-garmin-dump-import-job.test.ts
  • src/jobs/process-garmin-dump-import-job.ts
  • src/jobs/queues.ts
  • src/providers/garmin-dump.ts

Comment thread src/jobs/process-garmin-dump-import-job.ts Outdated

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Asherlc has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codereviewbot-ai

codereviewbot-ai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

Pull Request Review Summary

The changes in this PR are generally well-structured and introduce a great optimization by batching Garmin FIT file imports and clearing large arrays/maps to free up memory before processing.

However, there are two critical logic bugs in src/jobs/process-garmin-dump-import-job.ts that have been addressed in the inline comment:

  1. Crash on zero FIT files: If a Garmin dump has 0 FIT files, the job incorrectly throws a "missing" error and crashes the import.
  2. Dropped partial failures: If some batches succeed and some fail, the failures from the unsuccessful batches are silently swallowed instead of being combined with the successful ones.

I have posted an inline comment with a committable suggestion to fix both issues. Once that is applied, the PR is good to go!


🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does.

Comment thread src/jobs/process-garmin-dump-import-job.ts
- Guard missing-batch-result error with totalFitFiles > 0 check
- Always push batchFailures into fitResult.errors instead of
  dropping them via ?? when batchResult is non-null
- Add tests for zero-file imports and partial failure merging

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Asherlc has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours. Upgrade to a paid plan for unlimited reviews.

…tisfy Stryker

The PR-added array-clear lines (parsedDump.summaries/fitFiles/weightFitFiles = [])
were untestable memory-release mutations: nothing reads those properties afterward,
so Stryker's ArrayDeclaration mutants survived (score 0% < threshold 75, CI fail).

Spread-copy parsedDump.tempDirectories into preparedImport so parsedDump becomes
fully unreferenced after prepareGarminDumpImport returns. The local summaryByExternalId
map and the entire parsedDump object (including summaries/fitFiles/weightFitFiles and
their contents) are then GC'd together once the function returns, before the long
FIT import runs. This frees equal-or-more memory than the early clears while
removing the untestable mutants. No production test-only complexity or Stryker disable.
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours. Upgrade to a paid plan for unlimited reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Asherlc has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@Asherlc

Asherlc commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@CodeRabbit full rereview

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

@Asherlc Kicking off a full re-review of all changes in this PR.

✅ Action performed

Full review finished.

@Asherlc
Asherlc merged commit 798b876 into main Jul 15, 2026
100 checks passed
@Asherlc
Asherlc deleted the Asherlc/kinshasa-v1 branch July 15, 2026 21:06
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.

2 participants