Crear un Microservicio en Python que Llama a Otro en Spring Boot
Introducción: La Era de los Microservicios Poliglota
En la arquitectura moderna de software, los microservicios se han convertido en el estándar de facto para construir aplicaciones escalables y mantenibles. Uno de los desafíos más comunes en esta transición es la necesidad de integrar servicios escritos en diferentes lenguajes de programación. Este artículo te guiará paso a paso en cómo crear un microservicio en Python que se comunique de forma segura y eficiente con otro microservicio construido en Spring Boot.
La arquitectura poliglota no es una tendencia, es una realidad. Las organizaciones adoptan el lenguaje más apropiado para cada tarea: Python para machine learning y análisis de datos, Java/Spring Boot para sistemas críticos y escalables, Node.js para aplicaciones en tiempo real. La capacidad de que estos servicios conversen entre sí es fundamental.
¿Por Qué Integrar Python con Spring Boot?
Casos de Uso Reales
- Análisis de Datos en Tiempo Real: Un servicio Python con pandas, scikit-learn ejecuta análisis mientras Spring Boot maneja las transacciones.
- Microservicios Especializados: Python para NLP, visión por computadora; Spring Boot para lógica de negocio y persistencia.
- Sistemas Heredados: Expandir capacidades de sistemas Java existentes con nuevas funcionalidades en Python.
- Equipos Distribuidos: Diferentes equipos trabajan con sus lenguajes preferidos, integrados mediante APIs REST.
Ventajas de Esta Combinación
- Flexibilidad Tecnológica: Elige la herramienta correcta para cada problema
- Escalabilidad Independiente: Ambos servicios escalan según sus necesidades
- Mantenimiento Facilitado: Equipos especializados en cada tecnología
- Adopción Gradual: Migra o expande capacidades sin reescribir todo
Arquitectura de la Solución
Nuestra arquitectura consta de:
┌─────────────────────┐
│ Cliente/UI │
└──────────┬──────────┘
│
┌────▼─────────┐
│ Spring Boot │ (Puerto 8080)
│ Service │
│ (Orquestador)│
└────┬──────────┘
│ REST Call
│
┌────▼──────────┐
│ Python │ (Puerto 5000)
│ Microservicio│
│ (Procesador) │
└────┬──────────┘
│
┌────▼──────────┐
│ BD/Cache │
│ (Datos) │
└───────────────┘
Paso 1: Crear el Microservicio en Python
1.1 Configuración del Proyecto
mkdir python-microservice
cd python-microservice
python3 -m venv venv
source venv/bin/activate
pip install flask flask-cors requests python-dotenv
pip freeze > requirements.txt
1.2 Archivo Principal (app.py)
from flask import Flask, jsonify, request
from flask_cors import CORS
from dotenv import load_dotenv
import os
import logging
load_dotenv()
app = Flask(__name__)
CORS(app)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
from routes.api import api_bp
app.register_blueprint(api_bp)
@app.route('/health', methods=['GET'])
def health_check():
return jsonify({
'status': 'healthy',
'service': 'python-microservice',
'version': '1.0.0'
}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(os.getenv('FLASK_PORT', 5000)))
1.3 Servicios Principales (services/processor.py)
import requests
import logging
from typing import Dict, Any, Optional
from config import config
logger = logging.getLogger(__name__)
class DataProcessor:
def __init__(self):
self.spring_url = config.SPRING_BOOT_URL
self.timeout = config.REQUEST_TIMEOUT
def send_to_spring_boot(self, endpoint: str, data: Dict[str, Any], method: str = 'POST') -> Optional[Dict[str, Any]]:
try:
url = f"{self.spring_url}{endpoint}"
logger.info(f"Enviando {method} a {url}")
if method.upper() == 'POST':
response = requests.post(url, json=data, timeout=self.timeout)
elif method.upper() == 'GET':
response = requests.get(url, timeout=self.timeout)
else:
raise ValueError(f"Método no soportado: {method}")
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
logger.error(f"Timeout conectando a {self.spring_url}")
raise
except Exception as e:
logger.error(f"Error: {str(e)}")
raise
processor = DataProcessor()
Paso 2: Crear el Microservicio en Spring Boot
2.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-microservice</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
2.2 UserService.java
package com.example.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.example.dto.UserRequest;
import com.example.dto.UserResponse;
@Service
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
private final RestTemplate restTemplate;
@Value("${python.microservice.url}")
private String pythonMicroserviceUrl;
public UserService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public UserResponse processUserData(UserRequest request) {
try {
logger.info("Procesando usuario: {}", request.getUserId());
String pythonUrl = pythonMicroserviceUrl + "/api/process";
UserResponse pythonResponse = restTemplate.postForObject(pythonUrl, request, UserResponse.class);
logger.info("Respuesta Python recibida");
return new UserResponse(true, request.getUserId(), "Procesamiento completado", pythonResponse);
} catch (Exception e) {
logger.error("Error llamando a servicio Python: {}", e.getMessage());
return new UserResponse(false, request.getUserId(), "Error: " + e.getMessage(), null);
}
}
}
2.3 UserController.java
package com.example.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.example.dto.UserRequest;
import com.example.dto.UserResponse;
import com.example.service.UserService;
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("/process")
public ResponseEntity<UserResponse> processUser(@RequestBody UserRequest request) {
UserResponse response = userService.processUserData(request);
return ResponseEntity.status(response.isSuccess() ? HttpStatus.OK : HttpStatus.BAD_REQUEST).body(response);
}
}
Paso 3: Docker Compose
version: '3.8'
services:
python-service:
build:
context: ./python-microservice
ports:
- "5000:5000"
environment:
- SPRING_BOOT_URL=http://spring-boot-service:8080
spring-boot-service:
build:
context: ./spring-boot-microservice
ports:
- "8080:8080"
Paso 4: Testing de la Integración
curl -X POST http://localhost:5000/api/process \
-H "Content-Type: application/json" \
-d '{"user_id": 123, "action": "update"}'
Consideraciones de Producción
- Autenticación: Implementar JWT o OAuth2
- Circuit Breaker: Usar Resilience4j
- Rate Limiting: Proteger endpoints
- Observabilidad: Logging distribuido y tracing
- Configuración: Usar variables de entorno
- Pruebas: Aumentar cobertura de tests
Conclusión
Integrar Python con Spring Boot permite construir arquitecturas modernas, escalables y mantenibles. Esta guía te proporciona los fundamentos para empezar. Los microservicios poliglotas son el futuro del desarrollo de software.
Top comments (0)