[shareddump/feedbackfunctions] YouTube API performance improvements#253
[shareddump/feedbackfunctions] YouTube API performance improvements#253jamesmontemagno wants to merge 1 commit into
Conversation
1. Parallelize ProcessVideo calls with SemaphoreSlim(3): Replace serial foreach loops in GetYouTubeFeedback and SearchVideos with Task.WhenAll capped at 3 concurrent requests via SemaphoreSlim to reduce wall-clock time from O(N) to ~O(N/3). 2. Batch video metadata API calls: Add ProcessVideosBatch() to IYouTubeService and YouTubeService. Uses a single videos?part=snippet request for up to 50 IDs at once instead of N individual calls, saving both latency and YouTube quota units. 3. Add blob caching for YouTube results: Per-video cache (1-hour TTL) in GetYouTubeFeedback and per-search-query cache (30-minute TTL) in GetRecentYouTubeVideos, keyed in youtube-cache container. Modeled after the existing hackernews-cache pattern. 4. Remove artificial Task.Delay(1500) in YouTubeFeedbackService that added 1.5s of unnecessary wait per video during playlist analysis. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Staging Deployment Ready! Your changes from commit 🌐 Staging URL: https://staging.feedbackflow.app You can test your changes there before merging to production. This comment will be updated with each new commit to this PR. |
|
⚡ Functions Staging Deployment Ready! Your Azure Functions changes from commit 🔗 Functions Staging URL: https://feedbackfunctions20250414121421-staging.azurewebsites.net You can test your API endpoints and functions there before merging to production. This comment will be updated with each new commit to this PR. |
There was a problem hiding this comment.
Pull request overview
This PR improves the YouTube integration’s wall-clock performance and API quota usage by batching video metadata requests, parallelizing comment collection with bounded concurrency, and adding blob-backed caching in the Azure Functions layer. It also removes an unnecessary UI-side delay when analyzing playlist videos.
Changes:
- Added
ProcessVideosBatch(...)to batch video snippet lookups (50 IDs/request) and fetch comments concurrently (capped withSemaphoreSlim). - Introduced Azure Blob Storage caching for YouTube results (per-video cache for
GetYouTubeFeedback, per-query cache forGetRecentYouTubeVideos) via a newyoutube-cachecontainer. - Removed an artificial
Task.Delay(1500)from the web app’s YouTube analysis loop.
Show a summary per file
| File | Description |
|---|---|
shareddump/Services/Interfaces/IYouTubeService.cs |
Extends the YouTube service contract with ProcessVideosBatch. |
shareddump/Models/YouTube/YouTubeService.cs |
Implements batched metadata retrieval and bounded-parallel comment fetching. |
shareddump/Models/YouTube/YouTubeApiModels.cs |
Adds API models to support videos?part=snippet&id=... batch responses containing id. |
shareddump/Json/YouTubeJsonContext.cs |
Registers new YouTube batch-response models for source-gen serialization. |
shareddump/Services/Mock/MockYouTubeService.cs |
Adds mock implementation for ProcessVideosBatch and routes ProcessVideo through it. |
feedbackfunctions/FeedbackAnalysis/FeedbackFunctions.cs |
Adds per-video blob cache + switches to ProcessVideosBatch for uncached IDs. |
feedbackfunctions/Feeds/ContentFeedFunctions.cs |
Adds per-search-query blob cache for recent video search results. |
feedbackfunctions/Services/Storage/StorageNames.cs |
Introduces YouTubeCacheContainer constant. |
feedbackfunctions/Services/Storage/FeedbackStorageClients.cs |
Wires YouTubeCacheContainer into the shared storage client. |
feedbackwebapp/Services/Feedback/YouTubeFeedbackService.cs |
Removes unnecessary per-video analysis delay. |
feedbackflow.tests/TableInitializationServiceTests.cs |
Updates test helper to account for the added storage client dependency. |
Copilot's findings
- Files reviewed: 11/11 changed files
- Comments generated: 4
| outputVideos = [.. allVideoIds | ||
| .Select(id => outputVideos.FirstOrDefault(v => v.Id == id)) | ||
| .Where(v => v is not null) | ||
| .Select(v => v!)]; |
| public ContentFeedFunctions( | ||
| ILogger<ContentFeedFunctions> logger, | ||
| IHackerNewsService hackerNewsService, | ||
| IYouTubeService youtubeService, | ||
| IRedditService redditService, |
| AuthenticationMiddleware authMiddleware, | ||
| IUserAccountService userAccountService, | ||
| ITwitterThreadCacheService twitterThreadCacheService, | ||
| IFeatureGateService featureGateService) | ||
| IFeatureGateService featureGateService, | ||
| FeedbackStorageClients storageClients) |
| _logger.LogInformation("YouTube search cache hit for key {CacheKey}", cacheKey); | ||
| var cachedResponse = req.CreateResponse(HttpStatusCode.OK); | ||
| await cachedResponse.WriteAsJsonAsync(cachedVideos); | ||
| await user!.TrackUsageAsync(UsageType.FeedQuery, _userAccountService, _logger, $"Topic: {topic ?? tag}, Videos: {cachedVideos.Count} (cached)"); | ||
| return cachedResponse; |
Summary
Three targeted performance improvements to the YouTube API integration, plus a bonus bug fix.
1. Parallelize
ProcessVideocalls withSemaphoreSlim(3)Before: Videos were processed one-at-a-time in a
foreachloop. Each call made 2+ serial HTTP round-trips to YouTube. A 10-video playlist = ~20+ serial HTTP calls.After: New
ProcessVideosBatch(IEnumerable<string> videoIds)method usesTask.WhenAllcapped at 3 concurrent requests viaSemaphoreSlim— reducing wall-clock time from O(N) to ~O(N/3). BothGetYouTubeFeedbackandSearchVideosnow use this.2. Batch video metadata into a single API call
Before:
ProcessVideomade a separatevideos?part=snippet&id={singleId}call per video — N calls for N videos.After:
ProcessVideosBatchbatches all video IDs (up to 50 per request, per YouTube's API limit) into a singlevideos?part=snippetcall using the newYouTubeVideoResponseWithId/YouTubeVideoItemWithIdmodels. Saves both latency and precious YouTube quota units (10,000/day limit).3. Add blob caching for YouTube results
Before:
GetYouTubeFeedbackandGetRecentYouTubeVideoshad no caching — every request hit the YouTube API live. (HackerNews already had blob caching; YouTube didn't.)After:
GetYouTubeFeedback: Per-video cache with 1-hour TTL, stored in a newyoutube-cacheblob container. Only uncached video IDs hit the API.GetRecentYouTubeVideos: Per-search-query cache with 30-minute TTL, keyed bysearch-{topic}-{tag}-{days}d.json.Bonus: Remove artificial
Task.Delay(1500)bug fixYouTubeFeedbackService.cshad a hardcodedawait Task.Delay(1500)inside the per-video playlist analysis loop — adding 1.5 × N seconds of dead wait for no reason. Removed.Files Changed
shareddump/Services/Interfaces/IYouTubeService.csProcessVideosBatchto interfaceshareddump/Models/YouTube/YouTubeService.csProcessVideosBatchwith batching + parallelismshareddump/Models/YouTube/YouTubeApiModels.csYouTubeVideoResponseWithId/YouTubeVideoItemWithIdshareddump/Json/YouTubeJsonContext.csshareddump/Services/Mock/MockYouTubeService.csProcessVideosBatchin mockfeedbackfunctions/FeedbackAnalysis/FeedbackFunctions.csProcessVideosBatch, add per-video blob cachefeedbackfunctions/Feeds/ContentFeedFunctions.csGetRecentYouTubeVideosfeedbackfunctions/Services/Storage/StorageNames.csYouTubeCacheContainerconstantfeedbackfunctions/Services/Storage/FeedbackStorageClients.csYouTubeCacheContainerpropertyfeedbackwebapp/Services/Feedback/YouTubeFeedbackService.csTask.Delay(1500)feedbackflow.tests/TableInitializationServiceTests.cs