From edc4b4bbd52536367e90eebf00d0176e43096652 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 3 Nov 2025 13:04:40 +0530 Subject: [PATCH] fix: set multiprocessing start mode to `fork` instead of `forkserver` worker-pool with fork workers seem to not pick up jobs otherwise - the test `test_multi_queue_burst_consumption_worker_pool` just times out. https://docs.python.org/3/whatsnew/3.14.html#concurrent-futures Signed-off-by: Akhil Narang --- frappe/utils/background_jobs.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index 34ac14d463..9c57ed5ddb 100644 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -2,6 +2,7 @@ import os import random import signal import socket +import sys import time from collections import defaultdict from collections.abc import Callable @@ -373,6 +374,7 @@ class FrappeWorker(Worker): def start_frappe_scheduler(self): from frappe.utils.scheduler import start_scheduler + # TODO: switch to multiprocessing.Process() after further investigating of fork -> forkserver Thread(target=start_scheduler, daemon=True).start() @@ -418,7 +420,6 @@ def start_worker_pool( WARNING: This feature is considered "EXPERIMENTAL". """ - _start_sentry() # If gc.freeze is done then importing modules before forking allows us to share the memory @@ -447,9 +448,15 @@ def start_worker_pool( logging_level = "WARNING" # TODO: Make this true by default eventually. It's limited to RQ WorkerPool - no_fork = sbool(os.environ.get("FRAPPE_BACKGROUND_WORKERS_NOFORK", False)) + if sbool(os.environ.get("FRAPPE_BACKGROUND_WORKERS_NOFORK", False)): + worker_klass = FrappeWorkerNoFork + else: + if sys.version_info >= (3, 14): + import multiprocessing + + multiprocessing.set_start_method("fork", force=True) + worker_klass = FrappeWorker - worker_klass = FrappeWorkerNoFork if no_fork else FrappeWorker pool = WorkerPool( queues=queues, connection=redis_connection,