Skip to content

fix: eliminate N+1 blob URL fetches and limit concurrency#21

Closed
sentry[bot] wants to merge 1 commit into
integrationfrom
seer/fix/n-plus-1-blob-fetches
Closed

fix: eliminate N+1 blob URL fetches and limit concurrency#21
sentry[bot] wants to merge 1 commit into
integrationfrom
seer/fix/n-plus-1-blob-fetches

Conversation

@sentry

@sentry sentry Bot commented Jun 2, 2026

Copy link
Copy Markdown

Description

This PR addresses the N+1 API Call issue (SABLE-3H) observed for blob: URLs and reduces concurrency for other media fetches.

Problem:
On initial page load, when many components (e.g., room avatars/thumbnails) render simultaneously, useBlobCache was triggering an N+1 API call pattern. Specifically, the trace showed numerous GET blob:https://sable.cloudhub.social/... requests. These blob: URLs are already in-memory object URLs, so re-fetching them was redundant and inefficient. Additionally, for actual remote media URLs, a large number of concurrent fetches could occur, leading to network contention and performance issues.

Solution:

  1. Eliminate redundant blob: URL fetches: A check was added to useBlobCache to detect if the provided URL is already a blob: URL. If so, it's immediately treated as cached and returned, bypassing any network fetch() call. This directly resolves the N+1 issue for blob: URLs.
  2. Implement concurrency limiting for remote fetches: A module-scoped concurrency limiter (MAX_CONCURRENT_FETCHES = 4) was introduced in useBlobCache. This ensures that only a limited number of remote media fetches can occur simultaneously. Any additional requests are queued, preventing a burst of network activity and reducing the likelihood of N+1 detection for remote resources.
  3. Enhanced Observability: The HealthMonitor in ClientNonUIFeatures.tsx was updated to report the queueDepth of the blob fetch queue as a Sentry metric (sable.media.fetch_queue_depth). This allows for monitoring the effectiveness of the concurrency limiter and identifying potential bottlenecks.

These changes significantly reduce unnecessary network activity and improve the perceived performance of the application during initial load and when rendering lists of media.

Fixes SABLE-3H

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

AI disclosure:

  • Partially AI assisted (clarify which code was AI assisted and briefly explain what it does).
  • Fully AI generated (explain what all the generated code does in moderate detail).

Fixes SABLE-3H

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

⚠️ Missing changeset

This pull request does not include a changeset. Please add one before requesting review so the change is properly documented and included in the release notes.

How to add a changeset:

  1. Run pnpm run document-change (interactive) and commit the generated file, or
  2. Manually create .changeset/<descriptive-name>.md:
---
default: patch
---

Short user-facing summary of the change.

Replace patch with major, minor, patch, docs, or note as appropriate.

📖 Read more in CONTRIBUTING.md.

If this PR is internal/maintenance with no user-facing impact, a maintainer can add the internal label to skip this check.

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

Status Preview URL Commit Alias Updated (UTC)
✅ Deployment successful! https://pr-21-sable.justin-tech.workers.dev 5c44822 pr-21 Tue, 02 Jun 2026 20:35:59 GMT

@Just-Insane Just-Insane changed the base branch from dev to integration June 2, 2026 21:04
@Just-Insane Just-Insane marked this pull request as ready for review June 2, 2026 21:11
Copilot AI review requested due to automatic review settings June 2, 2026 21:11
Just-Insane added a commit that referenced this pull request Jun 2, 2026
Merged changes from #21 (Sentry bot PR):

1. **Eliminate redundant `blob:` URL fetches**: Added check to detect if
   URL is already a `blob:` URL. If so, bypass network fetch and use
   directly from memory. Resolves N+1 API call pattern on initial load.

2. **Implement concurrency limiting**: Added module-scoped concurrency
   limiter (MAX_CONCURRENT_FETCHES = 4) to cap simultaneous remote media
   fetches. Requests exceeding limit are queued, preventing network
   contention and N+1 detection for remote resources.

3. **Enhanced observability**: Updated HealthMonitor to report queueDepth
   as Sentry metric (sable.media.fetch_queue_depth) for monitoring
   concurrency limiter effectiveness.

Changes integrated into existing Cache API implementation in integration
branch while preserving auth failure tracking and persistent cache logic.

Fixes SABLE-3H
@Just-Insane Just-Insane closed this Jun 2, 2026

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

Pull request overview

This PR optimizes media fetching in the client by avoiding redundant fetches for in-memory blob: object URLs and by adding a concurrency limiter for remote media fetches, with added Sentry metrics to monitor cache and queue behavior.

Changes:

  • Short-circuit useBlobCache for blob: URLs to prevent redundant re-fetching.
  • Add a module-scoped concurrency limiter (max 4) to reduce simultaneous remote media fetches.
  • Extend HealthMonitor Sentry metrics to report the blob fetch queue depth.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/app/pages/client/ClientNonUIFeatures.tsx Adds Sentry metric for blob fetch queue depth (and consumes updated cache stats).
src/app/hooks/useBlobCache.ts Avoids fetching blob: URLs and introduces a concurrency-limited fetch queue for remote URLs, expanding cache stats.
Comments suppressed due to low confidence (1)

src/app/pages/client/ClientNonUIFeatures.tsx:590

  • After introducing the fetch queue, the count from inflightRequests.size no longer represents active network requests; it includes queued work too. This makes the sable.media.inflight_requests gauge and the “High inflight request count” breadcrumb message misleading. Consider reporting activeFetchCount as inflight, and optionally emit pendingCount (active + queued) / keep the breadcrumb threshold on pending to preserve N+1 observability.
      const { cacheSize, inflightCount, queueDepth } = getBlobCacheStats();
      Sentry.metrics.gauge('sable.media.blob_cache_size', cacheSize);
      if (inflightCount > 0) {
        Sentry.metrics.gauge('sable.media.inflight_requests', inflightCount);
        if (inflightCount >= 10) {

Comment on lines +31 to 41
export function getBlobCacheStats(): {
cacheSize: number;
inflightCount: number;
queueDepth: number;
} {
return {
cacheSize: imageBlobCache.size,
inflightCount: inflightRequests.size,
queueDepth: fetchQueue.length,
};
}
@Just-Insane Just-Insane deleted the seer/fix/n-plus-1-blob-fetches branch June 3, 2026 13:08
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