DRY in futures exception handling

This commit is contained in:
taoky 2024-08-27 21:39:35 +08:00
parent 99fabce7b8
commit cd40fc1f40

View File

@ -2,7 +2,7 @@
import sys import sys
from types import FrameType from types import FrameType
from typing import IO, Any, Callable, Generator, Literal, Optional from typing import IO, Any, Callable, Generator, Literal, NoReturn, Optional
import xmlrpc.client import xmlrpc.client
from dataclasses import dataclass from dataclasses import dataclass
import re import re
@ -18,7 +18,7 @@ from os.path import (
) # fast path computation, instead of accessing real files like pathlib ) # fast path computation, instead of accessing real files like pathlib
from contextlib import contextmanager from contextlib import contextmanager
import sqlite3 import sqlite3
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import Future, ThreadPoolExecutor, as_completed
import signal import signal
import tomllib import tomllib
from copy import deepcopy from copy import deepcopy
@ -65,6 +65,13 @@ def exit_handler(signum: int, frame: Optional[FrameType]) -> None:
signal.signal(signal.SIGTERM, exit_handler) signal.signal(signal.SIGTERM, exit_handler)
def exit_with_futures(futures: dict[Future, Any]) -> NoReturn:
logger.info("Exiting...")
for future in futures:
future.cancel()
sys.exit(1)
class LocalVersionKV: class LocalVersionKV:
""" """
A key-value database wrapper over sqlite3. A key-value database wrapper over sqlite3.
@ -593,10 +600,7 @@ class SyncBase:
) )
raise raise
except: except:
logger.info("Get an exception, exiting...") exit_with_futures(futures)
for future in futures:
future.cancel()
sys.exit(1)
logger.info("%s packages to update in check_and_update()", len(to_update)) logger.info("%s packages to update in check_and_update()", len(to_update))
return self.parallel_update(to_update, prerelease_excludes) return self.parallel_update(to_update, prerelease_excludes)
@ -635,10 +639,7 @@ class SyncBase:
logger.info("dumping local db...") logger.info("dumping local db...")
self.local_db.dump_json() self.local_db.dump_json()
except (ExitProgramException, KeyboardInterrupt): except (ExitProgramException, KeyboardInterrupt):
logger.info("Get ExitProgramException or KeyboardInterrupt, exiting...") exit_with_futures(futures)
for future in futures:
future.cancel()
sys.exit(1)
return success return success
def do_sync_plan( def do_sync_plan(
@ -1240,11 +1241,7 @@ def verify(
logger.warning("%s generated an exception", sname, exc_info=True) logger.warning("%s generated an exception", sname, exc_info=True)
success = False success = False
except (ExitProgramException, KeyboardInterrupt): except (ExitProgramException, KeyboardInterrupt):
# TODO: dup code in threading exception handler exit_with_futures(futures)
logger.info("Get ExitProgramException or KeyboardInterrupt, exiting...")
for future in futures:
future.cancel()
sys.exit(1)
# Part 2: iterate packages # Part 2: iterate packages
def unlink_not_in_set(first_dirname: str, position: int) -> None: def unlink_not_in_set(first_dirname: str, position: int) -> None:
@ -1275,10 +1272,7 @@ def verify(
logger.warning("%s generated an exception", sname, exc_info=True) logger.warning("%s generated an exception", sname, exc_info=True)
success = False success = False
except (ExitProgramException, KeyboardInterrupt): except (ExitProgramException, KeyboardInterrupt):
logger.info("Get ExitProgramException or KeyboardInterrupt, exiting...") exit_with_futures(futures)
for future in futures:
future.cancel()
sys.exit(1)
logger.info("Verification finished. Success: %s", success) logger.info("Verification finished. Success: %s", success)