Skip to content

Conversation

@fabiovincenzi
Copy link
Contributor

@fabiovincenzi fabiovincenzi commented Oct 13, 2025

Issue: #1207

Summary

Two-tier cache system for faster git operations: persistent bare repos + ephemeral working copies.

Architecture

  • .remote/cache/ - Shared bare repositories (persistent)
  • .remote/work/<push-id>/ - Per-push working copies (temporary)

Configuration

Add to proxy.config.json:

{
  "cache": {
    "maxSizeGB": 2,
    "maxRepositories": 50,
    "cacheDir": "./.remote/cache"
  }
}

Security

  • Each push gets unique working copy (.remote/work//)
  • Bare cache contains only git objects (no user files, no credentials)
  • sanitizeRepositoryConfig() immediately removes credentials from git config
  • Working copies deleted after push completes

@netlify
Copy link

netlify bot commented Oct 13, 2025

Deploy Preview for endearing-brigadeiros-63f9d0 canceled.

Name Link
🔨 Latest commit e67ff36
🔍 Latest deploy log https://app.netlify.com/projects/endearing-brigadeiros-63f9d0/deploys/690e128af32d60000894a9b7

@codecov
Copy link

codecov bot commented Oct 13, 2025

Codecov Report

❌ Patch coverage is 82.19178% with 39 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.27%. Comparing base (df6406b) to head (e67ff36).

Files with missing lines Patch % Lines
src/proxy/processors/push-action/git-operations.ts 66.66% 16 Missing and 3 partials ⚠️
src/proxy/processors/push-action/cache-manager.ts 85.89% 8 Missing and 3 partials ⚠️
src/proxy/processors/push-action/pullRemote.ts 84.31% 8 Missing ⚠️
src/proxy/processors/push-action/clearBareClone.ts 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1246      +/-   ##
==========================================
- Coverage   83.36%   83.27%   -0.10%     
==========================================
  Files          70       73       +3     
  Lines        3005     3204     +199     
  Branches      499      545      +46     
==========================================
+ Hits         2505     2668     +163     
- Misses        397      427      +30     
- Partials      103      109       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fabiovincenzi fabiovincenzi marked this pull request as ready for review October 22, 2025 14:13
Copy link
Contributor

@06kellyjac 06kellyjac left a comment

Choose a reason for hiding this comment

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

I'm looking forward to faster pulls!

Caches are a common place for logic or security problems so we may want added scrutiny and testing for this PR to be extra safe :)

Added some thoughts, not ran this locally just yet.

Comment on lines 10 to 22
if (process.env.NODE_ENV === 'test') {
// TEST: Full cleanup (bare cache + all working copies)
try {
if (fs.existsSync('./.remote')) {
fs.rmSync('./.remote', { recursive: true, force: true });
step.log('Test environment: Full .remote directory cleaned');
} else {
step.log('Test environment: .remote directory already clean');
}
} catch (err) {
step.log(`Warning: Could not clean .remote directory: ${err}`);
}
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like a safer option that ensures what we're testing more closely matches prod would be to either do some separate cleanup as necessary in the tests, or adjust config to have a much lower max (or even 0) then we can see if CacheManager itself is doing the cleanup.

Comment on lines 92 to 95
// Sort repositories by last accessed (oldest first for removal)
const reposToEvaluate = [...stats.repositories].sort(
(a, b) => a.lastAccessed.getTime() - b.lastAccessed.getTime(),
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice

Copy link
Contributor

Choose a reason for hiding this comment

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

I can't remember if we can use toSorted yet. If we still cant a comment to use toSorted in the future would help to find this later :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it should be available from node 20 so yes I'll use it

return 0;
}

return Math.round(totalBytes / (1024 * 1024)); // Convert to MB
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return Math.round(totalBytes / (1024 * 1024)); // Convert to MB
return Math.ceil(totalBytes / (1024 * 1024)); // Convert to MB

rounding down would hide some amount of KB up to 511KB. Not the end of the world but safest to always round up rather than be shortchanged.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's no conversion anymore since we are using bytes everywhere

Copy link
Contributor

@jescalada jescalada left a comment

Choose a reason for hiding this comment

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

Just a code review for now - I'll be testing the code later!

I was wondering if you could do some profiling to verify/document the speed improvements with this PR. Would be nice to try it out with massive repos (for example https://github.com/backstage/backstage which is >10GB) to see the difference.

I'll try to do some profiling soon as well 🙂

@06kellyjac
Copy link
Contributor

why on earth is backstage's repo 10GB? 😭
Even nixpkgs is only 6.1GB ATM on my machine

@jescalada
Copy link
Contributor

@06kellyjac It might be because of the tons of plugins that come with the repo (many of which have redundant components). Pulling with git clone --filter=blob:none https://github.com/backstage/backstage.git seems to make things a lot more speedy, however I'm not sure if we want to do things that way in the pullRemote. Perhaps a config option to filter out the BLOBs could help with these massive repos?

Copy link
Contributor

@jescalada jescalada left a comment

Choose a reason for hiding this comment

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

Did some manual testing and things seem to work great! When using the profiling script though, I had some issues with git clone hanging without any error messages on both the backend and the script execution.

I tried testing with Backstage which is massive and so hiccups like that are expected. However, we do want to make sure that even these large repos can get cloned correctly without fail, or at least give descriptive errors on fail.


| Metric | Without Cache (main) | With Cache (PR) | Improvement |
| ------------------- | -------------------- | --------------- | -------------------- |
| **Cold Push** | 20.63s | 17.58s | 15% faster |
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the Improvement column calculations might be incorrect 🤔 A push that took 20s and is now taking 6.68s is 20/6.68 = 2.99x faster.

I think it feels more impactful and easier to understand when formatting it as a multiplier (3x faster, etc.) rather than a percentage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right! The percentages were showing time reduction (66% of time saved) rather than the speedup multiplier. Updated to show it as a multiplier, which is much clearer and more impactful. Thanks!


# Configuration
PROXY_URL="http://localhost:8000"
GITHUB_REPO="${1:-fabiovincenzi/open-webui}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: We might want to add an explicit error message when executing benchmark-cache.sh but the chosen repo is not added to the authorised list.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just edited to show original errors everywhere


# Configuration
PROXY_URL="http://localhost:8000"
GITHUB_REPO="${1:-fabiovincenzi/open-webui}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we could also throw an error if the user didn't provide their own repo in the arguments rather than defaulting to your fork?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I tought i removed all the references of my github, I just realized I didn't commit those

echo ""

# Store results
echo "$push_number,$is_first,$CLONE_TIME,$PUSH_TIME,$TOTAL_TIME" >> results.csv
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should add the resulting .csvs to .gitignore? 🤔

echo -e "${GREEN}✓ Cache cleared${NC}"
echo ""

measure_push() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wonder if we could improve error handling here to prevent the script from hanging? I tried pulling my backstage fork but it strangely stopped responding on the 3rd push:

Image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think now the error handling shoud be much better, I'm sorry I didn't push latest changes

START_CLONE=$(date +%s.%N)

rm -rf "$REPO_NAME" 2>/dev/null || true
git clone "$PROXY_REPO_URL" "$REPO_NAME" > clone.log 2>&1
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we could output the clone status just to make sure things are going well for larger repos too?

Suggested change
git clone "$PROXY_REPO_URL" "$REPO_NAME" > clone.log 2>&1
git clone "$PROXY_REPO_URL" "$REPO_NAME" 2>&1 | tee clone.log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants