PHP客户端向Python后台守护进程传输user_id并实现多请求队列处理
解决方案:PHP向后台Python守护进程传参并实现多任务队列处理
我来给你一套落地的实现方案,既能让PHP把user_id传递给后台运行的Python守护进程,还能通过队列机制处理多个并发的user_id请求。核心思路是让Python守护进程监听一个Unix域套接字(比TCP套接字更轻量,适合本地进程通信),PHP通过这个套接字发送user_id,Python内部用线程安全的队列+线程池来异步处理任务。
1. Python守护进程实现(带队列+套接字监听)
这个脚本会在后台一直运行,监听Unix套接字接收user_id,把任务放到队列里,用线程池并行处理:
import socket import threading from concurrent.futures import ThreadPoolExecutor import os import sys # 配置项 UNIX_SOCKET_PATH = "/tmp/python_php_socket.sock" MAX_WORKERS = 3 # 同时处理的任务数 LOG_FILE = "/tmp/python_daemon.log" # 线程安全的任务队列 task_queue = [] queue_lock = threading.Lock() def log(message): """记录日志到文件""" with open(LOG_FILE, "a") as f: f.write(f"{message}\n") def process_user_id(user_id): """处理单个user_id的业务逻辑,这里替换成你的实际操作""" log(f"开始处理user_id: {user_id}") # 示例操作:模拟耗时任务 import time time.sleep(5) log(f"完成处理user_id: {user_id}") def queue_worker(): """队列消费线程,不断从队列取任务交给线程池处理""" with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: while True: user_id = None # 加锁取队列元素 with queue_lock: if task_queue: user_id = task_queue.pop(0) if user_id: executor.submit(process_user_id, user_id) # 短暂休眠,避免空轮询占用CPU threading.Event().wait(0.1) def daemonize(): """将进程转为守护进程""" # 第一次fork try: if os.fork() > 0: sys.exit(0) except OSError as e: log(f"第一次fork失败: {e}") sys.exit(1) # 脱离父进程环境 os.chdir("/") os.setsid() os.umask(0) # 第二次fork try: if os.fork() > 0: sys.exit(0) except OSError as e: log(f"第二次fork失败: {e}") sys.exit(1) # 重定向标准输入输出到/dev/null sys.stdout.flush() sys.stderr.flush() with open('/dev/null', 'r') as f: os.dup2(f.fileno(), sys.stdin.fileno()) with open('/dev/null', 'w') as f: os.dup2(f.fileno(), sys.stdout.fileno()) os.dup2(f.fileno(), sys.stderr.fileno()) def main(): # 转为守护进程 daemonize() log("Python守护进程已启动") # 启动队列消费线程 threading.Thread(target=queue_worker, daemon=True).start() # 创建并监听Unix套接字 try: # 如果套接字文件已存在,先删除 if os.path.exists(UNIX_SOCKET_PATH): os.unlink(UNIX_SOCKET_PATH) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind(UNIX_SOCKET_PATH) # 设置权限,让PHP进程能访问 os.chmod(UNIX_SOCKET_PATH, 0o777) sock.listen(5) log(f"正在监听Unix套接字: {UNIX_SOCKET_PATH}") while True: conn, addr = sock.accept() log("收到新连接") # 读取PHP发送的user_id(注意编码和换行) data = conn.recv(1024).decode('utf-8').strip() if data: log(f"收到user_id: {data}") # 加锁把任务加入队列 with queue_lock: task_queue.append(data) conn.close() except Exception as e: log(f"守护进程出错: {e}") # 清理套接字文件 if os.path.exists(UNIX_SOCKET_PATH): os.unlink(UNIX_SOCKET_PATH) sys.exit(1) if __name__ == "__main__": main()
2. PHP端发送user_id的代码
PHP通过Unix套接字连接到Python守护进程,发送user_id:
<?php $socket_path = '/tmp/python_php_socket.sock'; $user_id = 123; // 这里替换成你的实际user_id // 连接Unix套接字 $socket = fsockopen("unix://{$socket_path}", -1, $errno, $errstr, 5); if (!$socket) { die("连接失败: $errstr ($errno)"); } // 发送user_id(注意加换行,方便Python端接收) fwrite($socket, "{$user_id}\n"); fclose($socket); echo "user_id {$user_id} 已发送"; ?>
3. 部署与测试步骤
启动Python守护进程:
nohup python3 script.py &可以通过查看日志文件
/tmp/python_daemon.log确认进程是否启动成功。测试PHP调用:
直接访问你的PHP脚本,或者在命令行运行:php send_user_id.php然后查看Python的日志,会看到任务被接收并处理的记录。
处理多个并发请求:
可以同时调用多次PHP脚本,Python会把多个user_id加入队列,用线程池并行处理,不会阻塞新的请求。
关键细节说明
- Unix套接字权限:必须设置
0o777权限,确保PHP进程(通常是www-data用户)能访问套接字文件。 - 队列线程安全:用
threading.Lock()确保多个线程操作队列时不会出现数据混乱。 - 守护进程化:通过两次fork的标准方法实现守护进程,脱离终端后台运行。
- 日志记录:所有操作都记录到日志文件,方便排查问题。
内容的提问来源于stack exchange,提问作者Savage Panda
相关产品推荐
相关产品推荐

