Spawn a new dirty worker. Worker app assignment follows these priorities: 1. If there are pending respawns (from dead workers), use those apps 2. Otherwise, determine apps for a new worker based on allocation 3. If force_all_apps=True, spawn with all apps re
(self, force_all_apps=False)
| 929 | await asyncio.sleep(0.1) |
| 930 | |
| 931 | def spawn_worker(self, force_all_apps=False): |
| 932 | """ |
| 933 | Spawn a new dirty worker. |
| 934 | |
| 935 | Worker app assignment follows these priorities: |
| 936 | 1. If there are pending respawns (from dead workers), use those apps |
| 937 | 2. Otherwise, determine apps for a new worker based on allocation |
| 938 | 3. If force_all_apps=True, spawn with all apps regardless of limits |
| 939 | |
| 940 | Args: |
| 941 | force_all_apps: If True, spawn worker with all apps ignoring limits |
| 942 | |
| 943 | Returns: |
| 944 | Worker PID in parent process, or None if no apps need workers |
| 945 | """ |
| 946 | # Priority 1: Respawn dead worker with same apps |
| 947 | if self._pending_respawns: |
| 948 | app_paths = self._pending_respawns.pop(0) |
| 949 | elif force_all_apps: |
| 950 | # Force spawn with all apps (used by TTIN signal) |
| 951 | app_paths = list(self.app_specs.keys()) |
| 952 | else: |
| 953 | # Priority 2: New worker for initial pool |
| 954 | app_paths = self._get_apps_for_new_worker() |
| 955 | |
| 956 | if not app_paths: |
| 957 | self.log.debug("No apps need more workers, skipping spawn") |
| 958 | return None |
| 959 | |
| 960 | self.worker_age += 1 |
| 961 | socket_path = os.path.join( |
| 962 | self.tmpdir, f"worker-{self.worker_age}.sock" |
| 963 | ) |
| 964 | |
| 965 | worker = DirtyWorker( |
| 966 | age=self.worker_age, |
| 967 | ppid=self.pid, |
| 968 | app_paths=app_paths, # Only assigned apps, not all apps |
| 969 | cfg=self.cfg, |
| 970 | log=self.log, |
| 971 | socket_path=socket_path |
| 972 | ) |
| 973 | |
| 974 | pid = os.fork() |
| 975 | if pid != 0: |
| 976 | # Parent process |
| 977 | worker.pid = pid |
| 978 | self.workers[pid] = worker |
| 979 | self.worker_sockets[pid] = socket_path |
| 980 | |
| 981 | # Register which apps this worker has |
| 982 | self._register_worker_apps(pid, app_paths) |
| 983 | |
| 984 | self.cfg.dirty_post_fork(self, worker) |
| 985 | self.log.info("Spawned dirty worker (pid: %s) with apps: %s", |
| 986 | pid, app_paths) |
| 987 | return pid |
| 988 |
no test coverage detected