{"id":6881,"library":"simpervisor","title":"Simpervisor: Simple Async Process Supervisor","description":"Simpervisor is a lightweight Python library providing an asynchronous process supervisor. It offers the `SupervisedProcess` class to manage external processes with async methods like `start`, `ready`, `terminate`, and `kill`. The library is actively maintained, with its latest major release (1.0.0) in May 2023, indicating a stable but less frequent release cadence focused on robustness.","status":"active","version":"1.0.0","language":"python","source_language":"en","source_url":"https://github.com/jupyterhub/simpervisor","tags":["async","process","supervisor","asyncio","subprocess"],"install":[{"cmd":"pip install simpervisor","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"Required runtime environment","package":"Python","version":">=3.8"}],"imports":[{"symbol":"SupervisedProcess","correct":"from simpervisor import SupervisedProcess"}],"quickstart":{"code":"import asyncio\nimport sys\nimport os\nfrom simpervisor import SupervisedProcess\n\n# Create a dummy script to supervise\ndummy_script_content = \"\"\"\nimport asyncio\nimport sys\nimport time\n\nasync def child_process_task():\n    print(f\"Child process {os.getpid()} started.\")\n    try:\n        for i in range(5):\n            print(f\"Child process {os.getpid()}: Working... {i+1}/5\")\n            await asyncio.sleep(1)\n        print(f\"Child process {os.getpid()}: Done working, exiting.\")\n    except asyncio.CancelledError:\n        print(f\"Child process {os.getpid()}: Cancelled, cleaning up.\")\n    except Exception as e:\n        print(f\"Child process {os.getpid()}: Error - {e}\")\n    finally:\n        print(f\"Child process {os.getpid()} exiting gracefully.\")\n\nif __name__ == '__main__':\n    asyncio.run(child_process_task())\n\"\"\"\n\nasync def main():\n    script_path = \"./dummy_child_script.py\"\n    with open(script_path, \"w\") as f:\n        f.write(dummy_script_content)\n\n    print(\"Starting supervisor example...\")\n\n    # Supervise the dummy script using python as the executable\n    # This assumes 'python' is in your PATH\n    process = SupervisedProcess(\n        [sys.executable, script_path], # Command to run the child process\n        always_restart=False # For this example, don't restart automatically\n    )\n\n    await process.start()\n    print(f\"Supervisor: Process started with PID {process.pid}\")\n\n    await asyncio.sleep(2) # Give child some time to work\n\n    if await process.ready():\n        print(\"Supervisor: Child process reports ready (or has started).\")\n    else:\n        print(\"Supervisor: Child process not yet ready.\")\n\n    await asyncio.sleep(3)\n\n    print(\"Supervisor: Attempting to terminate child process...\")\n    await process.terminate()\n    # await process.wait() # Can wait for termination if needed\n\n    if not process.running:\n        print(\"Supervisor: Child process terminated.\")\n    else:\n        print(\"Supervisor: Child process is still running after terminate attempt.\")\n\n    os.remove(script_path)\n    print(\"Supervisor: Example finished.\")\n\nif __name__ == '__main__':\n    asyncio.run(main())\n","lang":"python","description":"This example demonstrates how to use `SupervisedProcess` to start an asynchronous Python script as a child process, monitor its status with `ready()`, and gracefully terminate it using `terminate()`. The child process simulates some work before exiting or being cancelled. The `sys.executable` is used to ensure the same Python interpreter runs the child script."},"warnings":[{"fix":"Remove the `loop=...` argument from `SupervisedProcess` instantiation and method calls. `simpervisor` now automatically uses `asyncio.get_running_loop()`.","message":"The `loop` argument was removed from the `SupervisedProcess` constructor and its methods (`start`, `ready`, `terminate`, `kill`) in version 1.0.0. If you were explicitly passing an `asyncio` event loop, this code will break.","severity":"breaking","affected_versions":"1.0.0 and later"},{"fix":"Thoroughly test `simpervisor` usage on Windows for your specific child processes. Consider alternative process management solutions for critical Windows deployments if issues persist.","message":"Running `SupervisedProcess` on Windows has historically encountered issues, particularly related to process termination and signal handling. While some fixes have been introduced, full cross-platform compatibility for all subprocess scenarios (especially complex ones) may not be guaranteed.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure all potentially blocking operations in your `asyncio` application are properly awaited or offloaded to a thread pool using `loop.run_in_executor()`.","message":"As `simpervisor` relies on `asyncio`, blocking the event loop within your async application (e.g., by calling synchronous I/O operations without `run_in_executor`) can prevent the supervisor from properly monitoring and managing child processes, leading to unresponsive behavior.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"search_vec":"'1.0.0':45 '2023':48 'activ':38 'async':3,27,60 'asynchron':14 'asyncio':63 'cadenc':56 'class':21 'extern':24 'focus':57 'frequent':54 'indic':49 'kill':34 'latest':42 'less':53 'librari':11,36 'lightweight':9 'like':29 'maintain':39 'major':43 'manag':23 'may':47 'method':28 'offer':18 'process':4,15,25,61 'provid':12 'python':10 'readi':31 'releas':44,55 'robust':59 'simpervisor':1,6 'simpl':2 'stabl':51 'start':30 'subprocess':64 'supervisedprocess':20 'supervisor':5,16,62 'termin':32","created_at":"2026-04-15T18:47:02.486780+00:00","updated_at":"2026-04-16T21:43:29.638084+00:00","problems":[{"fix":"pip install simpervisor","cause":"The `simpervisor` package has not been installed in the current Python environment.","error":"ModuleNotFoundError: No module named 'simpervisor'"},{"fix":"Prefix the method call with `await`, for example: `await process.start()`.","cause":"An asynchronous method of `SupervisedProcess` was called without the `await` keyword, meaning the coroutine was created but not executed.","error":"RuntimeWarning: coroutine 'SupervisedProcess.start' was never awaited"},{"fix":"Import `SupervisedProcess` and call `start` on an instance: `from simpervisor import SupervisedProcess; p = SupervisedProcess(...); await p.start()`.","cause":"`start` is an instance method of the `SupervisedProcess` class, not a top-level function importable directly from the `simpervisor` module.","error":"ImportError: cannot import name 'start' from 'simpervisor'"},{"fix":"Verify the command's spelling and ensure it is in your system's PATH or provide its full path.","cause":"The executable specified in the `command` list for `SupervisedProcess` could not be found by the operating system.","error":"FileNotFoundError: [Errno 2] No such file or directory: 'your_command_here'"},{"fix":"Access output using `await process.stdout_logs.get()` or `await process.stderr_logs.get()`, ensuring `capture_output=True` in the constructor.","cause":"`SupervisedProcess` does not directly expose `stdout`, `stdin`, or `stderr` attributes; it uses `stdout_logs` and `stderr_logs` queues for output management.","error":"AttributeError: 'SupervisedProcess' object has no attribute 'stdout'"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"1.0.0","cli_name":"","cli_version":null,"type":"library","homepage":null,"github":"https://github.com/jupyterhub/simpervisor#readme","docs":"https://github.com/jupyterhub/simpervisor#readme","changelog":null,"pypi":"https://pypi.org/project/simpervisor/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["devops","workflow"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-28","last_verified":"2026-06-28","next_check":"2026-07-28","install_tag":null}}