Skip to content

Conversation

@thromel
Copy link
Contributor

@thromel thromel commented Dec 9, 2025

Summary

This PR fixes the UI freezing/unresponsiveness issue reported in #54 where components become unresponsive while downloading, particularly with multiple YouTube downloads.

Root Causes Identified

  • Excessive UI re-renders (unbounded StateHasChanged calls on every progress update)
  • Database writes on every log line during YouTube downloads (100+ writes per download)
  • Fire-and-forget async event handlers in yt-dlp process output handling
  • Un-awaited InvokeAsync calls causing update queue buildup
  • File manager refresh triggered on every progress update (expensive operation)

Changes Made

UI Components (DownloadFromDirectLink.razor, DownloadVideoAudio.razor):

  • Added UI update throttling (500ms intervals) to limit StateHasChanged calls
  • Added file manager refresh throttling (2 second intervals)
  • Fixed un-awaited InvokeAsync calls
  • Fixed nested InvokeAsync patterns

YoutubeDownloadQueueService:

  • Implemented log batching using ConcurrentQueue - logs are queued in memory and flushed to database every 5 seconds instead of on every log line
  • Added FlushLogsAsync() method for explicit flushing on download completion
  • Reduces database writes from 100+/download to ~5-10/download

YtdlpService:

  • Replaced fire-and-forget async void event handlers with proper Channel<T>-based log processing
  • Process output/error events now write to a channel synchronously (non-blocking)
  • A dedicated task reads from the channel and properly awaits SignalR broadcasts
  • Ensures all logs are processed before download completion is signaled

Performance Improvements

Metric Before After
UI renders Unbounded (~1/sec/download) Max 2/sec total
DB writes (logs) Every log line (100+/download) Batched every 5s (~5-10/download)
File manager refresh Every progress update Every 2 seconds

Tests Added

  • 20 new unit tests for YoutubeDownloadQueueService
  • Includes thread safety test with 100 concurrent log appends
  • Tests for log batching, flushing, and persistence

Test Plan

  • Build succeeds with no new errors
  • All 128 unit tests pass
  • Manual test: Start 3+ YouTube downloads simultaneously and verify UI remains responsive
  • Manual test: Verify download logs are captured correctly after completion
  • Manual test: Verify progress updates still display (with slight delay due to throttling)

Fixes #54

This commit addresses the UI freezing issue that occurs when multiple
downloads are running simultaneously.

Changes:
- Add UI update throttling (500ms) to prevent excessive re-renders
- Add file manager refresh throttling (2s) for expensive operations
- Implement log batching in YoutubeDownloadQueueService (flushes every 5s
  instead of writing to DB on every log line)
- Replace fire-and-forget async event handlers in YtdlpService with
  proper Channel-based log processing
- Fix un-awaited InvokeAsync calls in Blazor components
- Add 20 unit tests for YoutubeDownloadQueueService including thread
  safety tests for concurrent log appends

The key improvements reduce database writes during YouTube downloads from
100+/download to ~5-10/download, and limit UI renders to 2/second max
instead of unbounded updates.
@gemini-code-assist
Copy link

Summary of Changes

Hello @thromel, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the application's UI responsiveness and backend performance, particularly when handling multiple concurrent YouTube downloads. It addresses several identified root causes of unresponsiveness, including excessive UI re-renders and frequent database writes, by introducing intelligent throttling mechanisms and a more efficient asynchronous log processing pipeline. The changes aim to provide a smoother user experience and reduce the load on the database during intensive operations.

Highlights

  • UI Responsiveness: Implemented UI update throttling (500ms) and file manager refresh throttling (2s) in Blazor components to prevent freezing during active downloads.
  • Database Performance: Introduced log batching for YouTube downloads, reducing database writes from 100+ per download to approximately 5-10 by flushing logs every 5 seconds instead of on every line.
  • Asynchronous Event Handling: Refactored yt-dlp process output handling from 'fire-and-forget' async event handlers to a robust Channel<T>-based system, ensuring all logs are processed and broadcast correctly without blocking.
  • Unit Tests: Added 20 new unit tests for the YoutubeDownloadQueueService, covering CRUD operations, log batching, concurrent log appends, and state management.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-advanced-security
Copy link

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an excellent pull request that addresses critical UI performance issues through well-thought-out changes like UI throttling, log batching, and safer async handling. The introduction of comprehensive unit tests is also a great addition. My review focuses on a couple of subtle but important concurrency issues in the new log batching mechanism to ensure its robustness and prevent data loss.

@thromel
Copy link
Contributor Author

thromel commented Dec 9, 2025

CI Note

The failing test Http2IntegrationTests.HttpClient_ShouldSupportCompression is a pre-existing issue unrelated to this PR.

The error is:

System.IO.FileNotFoundException : Could not find file '/tmp/MvcTestingAppManifest.json'

This is a known issue with WebApplicationFactory<T> in CI environments where the manifest file is not generated correctly. The same test failure occurs on the base branch (v3.0) as well - see run 19931909113.

All 20 new tests added in this PR pass successfully, and all other existing tests pass (127/128 passed, 1 pre-existing failure).

- Add SemaphoreSlim to prevent race conditions when multiple threads
  trigger FlushLogsAsync simultaneously for the same itemId
- Re-queue logs on DbUpdateConcurrencyException instead of silently
  discarding them, preventing potential data loss
- Strengthen test assertion to verify batching behavior by checking
  that subsequent logs within the flush interval are not immediately
  persisted
- Properly dispose of SemaphoreSlim in CleanupLogsForItem
The test was failing in CI because it accessed _factory.Services which
triggers WebApplicationFactory to start the server, causing a
FileNotFoundException for MvcTestingAppManifest.json.

The test doesn't actually need the factory - it only tests the local
TestHttpMessageHandler. Removed the unnecessary factory dependency to
fix the CI failure.
The test was using 'invalid<>name.txt' which contains characters that
are invalid on Windows but valid on Linux, causing the test to fail
in CI.

Changed to use 'invalid/name.txt' which contains a path separator that
is invalid in filenames on all platforms.
@gudarzi gudarzi merged commit 5cc4b92 into gudarzi:v3.0 Dec 10, 2025
4 of 6 checks passed
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.

Components become unresponsible while downloading

2 participants