Skip to content

Commit

Permalink
Run Function Executor process in its own process group on POSIX systems
Browse files Browse the repository at this point in the history
This allows us to kill all processes in Function Executor process group
instead of only killing the Function Executor process. This addresses the
use case when customer code forks processes. We now clean up the forked
processes too.

Testing:

make check
make test
  • Loading branch information
eabatalov committed Jan 2, 2025
1 parent d878f78 commit 25303e2
Showing 1 changed file with 13 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import asyncio
import os
import signal
from typing import Any, Optional

from .function_executor_server_factory import (
Expand Down Expand Up @@ -46,6 +48,8 @@ async def create(
proc: asyncio.subprocess.Process = await asyncio.create_subprocess_exec(
"indexify-cli",
*args,
# TODO: pass `process_group=0` instead of the depricated `preexec_fn` once we only support Python 3.11+.
preexec_fn=_new_process_group,
)
return SubprocessFunctionExecutorServer(
process=proc,
Expand Down Expand Up @@ -77,6 +81,10 @@ async def destroy(
# The process already exited and was waited() sucessfully.
return

if os.name == "posix":
# On POSIX systems, we can kill the whole process group so processes forked by customer code are also killed.
# This should be done before proc.kill because PG processes get their own PG when their PG leader dies.
os.killpg(proc.pid, signal.SIGKILL)
proc.kill()
await proc.wait()
except Exception as e:
Expand All @@ -100,3 +108,8 @@ def _release_port(self, port: int) -> None:

def _server_address(port: int) -> str:
return f"localhost:{port}"


def _new_process_group() -> None:
"""Creates a new process group with ID equal to the current process PID. POSIX only."""
os.setpgid(0, 0)

0 comments on commit 25303e2

Please sign in to comment.