Spring Boot微服务异步触发Python脚本并接收执行完成通知的最优方案
Hey Sudheer,我来给你梳理几个靠谱的实现方案,都是生产环境里常用的,还附了示例代码,你可以参考下~
最优方案推荐:基于消息队列的异步触发+回调(生产环境首选)
这个方案的核心是用消息队列(比如RabbitMQ、Kafka)实现Spring Boot和Python脚本的解耦,既能保证异步触发的可靠性,又能确保脚本执行完成后通知微服务。优势在于消息持久化、自动重试、解耦服务,完全适合生产环境的需求。
实现步骤
- Spring Boot将触发脚本的请求发送到消息队列的「任务队列」
- Python端监听「任务队列」,收到消息后执行目标脚本
- 脚本执行完成后,Python将结果发送到消息队列的「回调队列」
- Spring Boot监听「回调队列」,接收脚本执行完成的通知
示例代码
1. Spring Boot端(以RabbitMQ为例)
首先添加RabbitMQ依赖到pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
配置RabbitMQ队列和交换机:
import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMQConfig { // 任务队列:Spring Boot发送触发消息到这里 public static final String TASK_QUEUE = "python_script_task_queue"; // 回调队列:Python发送执行结果到这里 public static final String CALLBACK_QUEUE = "python_script_callback_queue"; @Bean public Queue taskQueue() { return new Queue(TASK_QUEUE, true); // 持久化队列 } @Bean public Queue callbackQueue() { return new Queue(CALLBACK_QUEUE, true); } }
发送触发消息的服务:
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.stereotype.Service; @Service public class ScriptTriggerService { private final RabbitTemplate rabbitTemplate; public ScriptTriggerService(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } // 异步触发Python脚本 public void triggerPythonScript(String scriptParam) { // 可以传递脚本需要的参数,比如JSON格式 rabbitTemplate.convertAndSend(RabbitMQConfig.TASK_QUEUE, scriptParam); System.out.println("已发送脚本触发请求,参数:" + scriptParam); } }
监听回调队列的消费者:
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class ScriptCallbackListener { @RabbitListener(queues = RabbitMQConfig.CALLBACK_QUEUE) public void handleScriptResult(String result) { // 处理脚本执行完成的通知,比如更新数据库、发送告警等 System.out.println("Python脚本执行完成,结果:" + result); // 这里可以写你的业务逻辑 } }
2. Python端(用pika库操作RabbitMQ)
首先安装依赖:
pip install pika
Python监听任务队列并执行脚本的代码:
import pika import subprocess # RabbitMQ连接配置 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # 声明队列(和Spring Boot端一致) channel.queue_declare(queue='python_script_task_queue', durable=True) channel.queue_declare(queue='python_script_callback_queue', durable=True) def execute_script(script_param): # 执行你的Python脚本,这里示例执行一个简单的脚本 # 替换成你的脚本路径和参数 result = subprocess.run(['python', '/path/to/your/script.py', script_param], capture_output=True, text=True) return result.stdout + result.stderr def callback(ch, method, properties, body): script_param = body.decode() print(f"收到脚本触发请求,参数:{script_param}") # 执行脚本 script_result = execute_script(script_param) # 发送回调消息到回调队列 channel.basic_publish(exchange='', routing_key='python_script_callback_queue', body=script_result) print(f"脚本执行完成,已发送结果到回调队列:{script_result}") # 确认消息已处理 ch.basic_ack(delivery_tag=method.delivery_tag) # 设置消费者,手动确认消息 channel.basic_consume(queue='python_script_task_queue', on_message_callback=callback) print("Python监听任务队列中...") channel.start_consuming()
轻量替代方案:REST API回调模式
如果你的项目不需要复杂的消息中间件,这个轻量方案更适合。核心是Spring Boot调用Python的API触发脚本,同时传递自己的回调URL,Python脚本执行完成后主动调用这个URL通知结果。
实现步骤
- Spring Boot暴露一个回调接口,用于接收脚本执行结果
- Spring Boot异步调用Python的触发接口,携带回调URL和脚本参数
- Python脚本执行完成后,调用Spring Boot的回调接口发送结果
示例代码
1. Spring Boot端
首先添加Web依赖到pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
回调接口:
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class ScriptCallbackController { @PostMapping("/api/script/callback") public void handleScriptCallback(@RequestBody String scriptResult) { System.out.println("收到Python脚本执行结果:" + scriptResult); // 处理结果的业务逻辑 } }
异步触发Python脚本的服务:
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class ScriptTriggerService { private final RestTemplate restTemplate; public ScriptTriggerService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @Async // 异步调用,不阻塞主线程 public void triggerPythonScript(String scriptParam) { String callbackUrl = "http://localhost:8080/api/script/callback"; // 构造请求参数,包含回调URL和脚本参数 String requestBody = String.format("{\"param\":\"%s\", \"callbackUrl\":\"%s\"}", scriptParam, callbackUrl); // 调用Python的触发接口 restTemplate.postForObject("http://localhost:5000/api/trigger-script", requestBody, String.class); System.out.println("已异步触发Python脚本"); } }
别忘了在启动类添加@EnableAsync注解开启异步支持:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableAsync public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
2. Python端(用Flask实现API)
首先安装依赖:
pip install flask requests
Python的API代码:
from flask import Flask, request import subprocess import requests app = Flask(__name__) def execute_script(script_param): # 执行你的脚本 result = subprocess.run(['python', '/path/to/your/script.py', script_param], capture_output=True, text=True) return result.stdout + result.stderr @app.route('/api/trigger-script', methods=['POST']) def trigger_script(): data = request.get_json() script_param = data.get('param') callback_url = data.get('callbackUrl') # 执行脚本 script_result = execute_script(script_param) # 调用Spring Boot的回调接口发送结果 requests.post(callback_url, data=script_result) return {"status": "success", "message": "脚本已触发执行"} if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
总结
- 生产环境首选方案一(消息队列):可靠性高、支持重试、服务解耦,适合脚本执行时间长、并发高的场景
- 轻量场景选方案二(REST回调):不需要中间件,代码简单,适合小型项目或快速原型开发
内容的提问来源于stack exchange,提问作者user3853393
相关产品推荐
相关产品推荐

