Prevent 'Too many open files' crash on store source switch
- Raise the process soft file-descriptor limit to the hard limit at startup (GLib aborts the process with 'Creating pipes for GWakeup: Too many open files' when cover/metadata loading exhausts a 1024-soft-limit environment). - Reduce per-loader network concurrency 8 -> 6 threads to lower socket pressure against the store server.
This commit is contained in:
+18
-2
@@ -136,7 +136,7 @@ class CoverLoader(QObject):
|
|||||||
def run(self):
|
def run(self):
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
|
||||||
pool = ThreadPoolExecutor(max_workers=8)
|
pool = ThreadPoolExecutor(max_workers=6)
|
||||||
futures = {
|
futures = {
|
||||||
pool.submit(load_cover, it): i
|
pool.submit(load_cover, it): i
|
||||||
for i, it in enumerate(self.items)
|
for i, it in enumerate(self.items)
|
||||||
@@ -1634,7 +1634,7 @@ class StoreCoverLoader(QObject):
|
|||||||
def run(self):
|
def run(self):
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
|
||||||
pool = ThreadPoolExecutor(max_workers=8)
|
pool = ThreadPoolExecutor(max_workers=6)
|
||||||
futures = {
|
futures = {
|
||||||
pool.submit(load_cover, it, 8, self.quick): row
|
pool.submit(load_cover, it, 8, self.quick): row
|
||||||
for row, it in self.tasks
|
for row, it in self.tasks
|
||||||
@@ -5954,8 +5954,24 @@ class MainWindow(QMainWindow):
|
|||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
|
|
||||||
|
def _raise_nofile_limit():
|
||||||
|
"""Raise the soft file-descriptor limit to the hard limit.
|
||||||
|
|
||||||
|
Cover/metadata loading opens many short-lived sockets, and each worker
|
||||||
|
QThread's GLib event dispatcher creates a wakeup pipe. On systems with a
|
||||||
|
1024 soft limit this aborts the process with GLib's "Too many open files".
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import resource
|
||||||
|
_soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||||
|
resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard))
|
||||||
|
except Exception: # noqa: BLE001 - best effort, never block startup
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)-7s %(name)-14s %(message)s")
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)-7s %(name)-14s %(message)s")
|
||||||
|
_raise_nofile_limit()
|
||||||
init_db() # migrate legacy on-share DB/covers to local storage, then schema
|
init_db() # migrate legacy on-share DB/covers to local storage, then schema
|
||||||
# Auto-ingest any missing DATs so scanning matches against the catalog
|
# Auto-ingest any missing DATs so scanning matches against the catalog
|
||||||
# even on a fresh/reset database (no manual `python -m app.ingest` step).
|
# even on a fresh/reset database (no manual `python -m app.ingest` step).
|
||||||
|
|||||||
Reference in New Issue
Block a user