Skip to content

Version 1.5.6#41

Merged
AlanRockefeller merged 2 commits intomainfrom
test
Feb 9, 2026
Merged

Version 1.5.6#41
AlanRockefeller merged 2 commits intomainfrom
test

Conversation

@AlanRockefeller
Copy link
Copy Markdown
Owner

@AlanRockefeller AlanRockefeller commented Feb 9, 2026

Summary by CodeRabbit

  • New Features

    • Ctrl-C support for graceful application shutdown and cleanup.
    • Optional debug timing logs for troubleshooting image operations.
  • Bug Fixes

    • Improved application shutdown stability with enhanced resource cleanup.
    • Reduced UI lag through optimized signal handling.
    • Enhanced image prefetch performance and responsiveness.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Walkthrough

This release (v1.5.6) introduces performance optimizations and stability improvements. Key changes include debounced emission of UI signals to reduce overhead, increased prefetch worker capacity and radius, cooperative shutdown with Ctrl-C handling, Qt-thread-safe callback ordering in prefetchers, and debug instrumentation for cache/timing analysis.

Changes

Cohort / File(s) Summary
Release Documentation
ChangeLog.md, pyproject.toml
Version bump to 1.5.6 with release notes documenting performance and stability improvements (debounced signals, prefetch tuning, shutdown refactoring, Ctrl-C support).
Performance & Prefetch Configuration
faststack/config.py, faststack/imaging/prefetch.py
Increased prefetch_radius from 4 to 6, expanded thread pool from 4 to 8 workers, raised initial prefetch radius from 2 to 4, increased directional bias from 0.70 to 0.85. Added debug timing logs and task counters with early-exit shutdown checks.
Application Lifecycle & Shutdown
faststack/app.py
Refactored shutdown into separate Qt-only (shutdown_qt) and background-safe (shutdown_nonqt) methods. Integrated Ctrl-C handling via SIGINT handler and periodic timer. Introduced debounced signal emission for metadata and highlight state changes to reduce UI churn during rapid navigation.
Prefetcher Thread Safety
faststack/thumbnail_view/prefetcher.py
Added stop signal (threading.Event) to prevent new work post-shutdown. Implemented Qt-thread callback dispatch when available with fallback. Improved cancellation safety via snapshot-under-lock pattern. Added executor shutdown with cancel_futures=True and robust guards against processing after stop.
Debug Instrumentation
faststack/ui/provider.py
Added optional timing logs (START/GOT/DONE) in ImageProvider.requestImage when debug_cache is enabled, tracing image request and color space handling durations without altering control flow.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SigHandler as Signal Handler
    participant QtTimer as Qt Timer
    participant AppController
    participant MainExecutor as Main/Prefetch Executor
    participant ThumbnailExecutor as Thumbnail Executor
    
    User->>SigHandler: Ctrl-C (SIGINT)
    SigHandler->>QtTimer: Request App Shutdown
    QtTimer->>AppController: Call shutdown()
    AppController->>AppController: shutdown_qt()
    Note over AppController: Stop timers, detach engine
    AppController->>MainExecutor: executor.shutdown(cancel_futures=True, wait=False)
    MainExecutor->>MainExecutor: Cancel pending tasks
    AppController->>ThumbnailExecutor: executor.shutdown(cancel_futures=True, wait=False)
    ThumbnailExecutor->>ThumbnailExecutor: Cancel pending tasks
    AppController->>AppController: shutdown_nonqt()
    Note over AppController: Cleanup background resources
    AppController->>User: Application exits
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Version 1.5.6' is directly related to the primary change: releasing version 1.5.6 with performance and stability improvements across multiple modules.
Docstring Coverage ✅ Passed Docstring coverage is 84.38% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@ChangeLog.md`:
- Around line 7-12: Update the two subsection headings from "#### Performance"
and "#### Stability" to use H3 (###) instead of H4 so they follow the parent H2
and match other sections (e.g., "### Changed", "### Fixed"); edit the heading
lines containing "Performance" and "Stability" to start with ###.
🧹 Nitpick comments (7)
faststack/ui/provider.py (1)

41-45: Move import time to module level; prefer log over print().

import time inside requestImage runs on every QML image request. While Python caches imports, the convention in this file is module-level imports. More importantly, the [DBGCACHE] output uses print() while the rest of the module (and prefetch.py's similar instrumentation) uses the log logger — this bypasses log-level filtering and any configured log handlers.

Suggested changes

At the top of the file (e.g., after line 5):

import time

Then in the method body:

-        import time
         _debug = getattr(self.app_controller, 'debug_cache', False)
         if _debug:
             _t_start = time.perf_counter()
-            print(f"[DBGCACHE] {_t_start*1000:.3f} requestImage: START id={id}")
+            log.info("[DBGCACHE] %.3f requestImage: START id=%s", _t_start*1000, id)

Apply the same printlog.info change on lines 86 and 136.

faststack/thumbnail_view/prefetcher.py (2)

93-102: Qt emitter setup assumes construction on the Qt/main thread.

The _ReadyEmitter QObject will have thread affinity to whatever thread constructs ThumbnailPrefetcher. The QueuedConnection on line 100 only delivers to the receiver's thread, so this works correctly as long as the prefetcher is constructed on the main thread. If that invariant ever changes, callbacks would not land on the Qt thread as intended.

Worth a brief comment or assertion if you want to harden this.


311-324: Consider logging cancelled-future exceptions at debug level.

The try/except Exception: pass on lines 321-324 silently swallows errors during cancel(). While this is a shutdown path, a log.debug would aid diagnosis if cancellation misbehaves.

Optional improvement
         for f in futures:
             try:
                 f.cancel()
-            except Exception:
-                pass
+            except Exception as exc:
+                log.debug("Error cancelling future during cancel_all: %s", exc)
faststack/imaging/prefetch.py (1)

221-224: Use module-level import time and log instead of print().

import time appears inside update_prefetch (line 222), submit_task (line 338), and _decode_and_cache (line 404). While cached by Python, scattering imports across methods is unconventional — move to the top of the file. Additionally, print() on lines 224, 322, and 341 bypasses the configured logging infrastructure; prefer log.info()/log.debug() for consistency with the other timing instrumentation already in this file.

Suggested fix (module top-level import)
 import logging
 import os
 import io
+import time
 import hashlib

Then remove the inline import time statements from lines 222, 338, and 404.

Also applies to: 318-322, 338-341

faststack/app.py (3)

722-724: Consider using log.debug() instead of print() for debug instrumentation.

All [DBGCACHE] instrumentation uses print(), bypassing the logging infrastructure. This means these messages can't be filtered by log level, won't appear in log files, and won't include standard log metadata (timestamps, module name). Since debug_cache is already a dedicated flag, log.debug() with the [DBGCACHE] prefix would integrate better with the existing logging setup while preserving the same gating behavior.


3497-3506: Log exceptions during shutdown cleanup instead of silently swallowing them.

The try/except/pass blocks here mask potential issues during shutdown. Even during cleanup, a brief log.debug helps diagnose problems when shutdown behaves unexpectedly.

♻️ Proposed fix
         try:
             self._metadata_debounce_timer.stop()
-        except Exception:
-            pass
+        except Exception as e:
+            log.debug("Failed to stop debounce timer: %s", e)

-        # Stop QFileSystemWatcher if it's Qt-based
         try:
             self.watcher.stop()
-        except Exception:
-            pass
+        except Exception as e:
+            log.debug("Failed to stop watcher: %s", e)

5582-5636: Robust shutdown-with-timeout pattern; minor cleanup opportunity.

The threading.Timer backstop + faulthandler.dump_traceback_later combo is a solid approach for preventing hung shutdowns while providing diagnostic output. Two small items:

  1. import threading at line 5583 is redundant — it's already imported at the top of the file (line 27).
  2. The try/except/pass at lines 5616-5619 should log the exception for consistency with the shutdown debugging intent.
♻️ Proposed cleanup
-    import threading
     import faulthandler
             try:
                 timer.stop()
-            except Exception:
-                pass
+            except Exception as e:
+                log.debug("Failed to stop SIGINT timer: %s", e)

Comment thread ChangeLog.md
@AlanRockefeller AlanRockefeller merged commit f72f78e into main Feb 9, 2026
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Mar 9, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Mar 25, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Apr 17, 2026
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.

1 participant