# Руководство по созданию микросервиса ## 🚀 Быстрый старт ### Шаг 1: Скопировать шаблон ```bash cp -r microservices/template_service microservices/my_new_service cd microservices/my_new_service ``` ### Шаг 2: Выбрать порт Выберите порт из диапазона **13000-14000**. Уже занятые: - 13001 - User Service Пусть ваш сервис будет на порту **13002**. ### Шаг 3: Создать proto файл Создайте `shared_proto/proto/my_service.proto`: ```protobuf syntax = "proto3"; package my_service; message GetDataRequest { string id = 1; } message Data { string id = 1; string content = 2; } service MyService { rpc GetData(GetDataRequest) returns (Data); } ``` ### Шаг 4: Обновить shared_proto/src/lib.rs Добавьте: ```rust pub mod my_service { tonic::include_proto!("my_service"); } ``` ### Шаг 5: Обновить shared_proto/build.rs Добавьте: ```rust tonic_build::compile_protos("proto/my_service.proto")?; ``` ### Шаг 6: Обновить microservices/my_new_service/Cargo.toml ```toml [package] name = "my_new_service" version.workspace = true edition.workspace = true authors.workspace = true [dependencies] tokio = { version = "1.35", features = ["full"] } axum = "0.7" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tower = "0.4" tower-http = { version = "0.5", features = ["trace"] } tracing = "0.1" tracing-subscriber = "0.3" tonic = "0.11" prost = "0.12" shared_proto = { path = "../../shared_proto" } ``` ### Шаг 7: Реализовать сервис Обновите `microservices/my_new_service/src/main.rs`: ```rust use tonic::{Request, Response, Status, transport::Server}; use shared_proto::my_service::{ my_service_server::{MyService, MyServiceServer}, GetDataRequest, Data, }; use tracing_subscriber; pub struct MyServiceImpl; #[tonic::async_trait] impl MyService for MyServiceImpl { async fn get_data( &self, request: Request, ) -> Result, Status> { let id = request.into_inner().id; tracing::info!("GetData called with id: {}", id); Ok(Response::new(Data { id: id.clone(), content: format!("Data for {}", id), })) } } #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt::init(); let addr = "127.0.0.1:13002".parse()?; let my_service = MyServiceImpl; tracing::info!("MyService gRPC server listening on {}", addr); Server::builder() .add_service(MyServiceServer::new(my_service)) .serve(addr) .await?; Ok(()) } ``` ### Шаг 8: Добавить в workspace Обновите корневой `Cargo.toml`: ```toml [workspace] members = [ "api_gateway", "api", "microservices/user_service", "microservices/my_new_service", "shared_proto" ] ``` ### Шаг 9: Скомпилировать ```bash cargo check # или cargo build ``` ## 📚 Примеры ### Пример 1: Сервис продуктов **shared_proto/proto/product.proto:** ```protobuf syntax = "proto3"; package product; message Product { int32 id = 1; string name = 2; float price = 3; } message GetProductRequest { int32 id = 1; } message CreateProductRequest { string name = 1; float price = 2; } service ProductService { rpc GetProduct(GetProductRequest) returns (Product); rpc CreateProduct(CreateProductRequest) returns (Product); } ``` **microservices/product_service/src/main.rs:** ```rust use tonic::{Request, Response, Status, transport::Server}; use shared_proto::product::{ product_service_server::{ProductService, ProductServiceServer}, GetProductRequest, Product, CreateProductRequest, }; use tracing_subscriber; pub struct ProductServiceImpl; #[tonic::async_trait] impl ProductService for ProductServiceImpl { async fn get_product( &self, request: Request, ) -> Result, Status> { let id = request.into_inner().id; Ok(Response::new(Product { id, name: "Product".to_string(), price: 99.99, })) } async fn create_product( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); Ok(Response::new(Product { id: 1, name: req.name, price: req.price, })) } } #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt::init(); let addr = "127.0.0.1:13002".parse()?; let service = ProductServiceImpl; tracing::info!("Product Service listening on {}", addr); Server::builder() .add_service(ProductServiceServer::new(service)) .serve(addr) .await?; Ok(()) } ``` ### Пример 2: Сервис заказов Использует User Service и Product Service: **microservices/order_service/src/main.rs:** ```rust use tonic::transport::Channel; use shared_proto::order::{ order_service_server::{OrderService, OrderServiceServer}, CreateOrderRequest, Order, }; use shared_proto::user::user_service_client::UserServiceClient; use shared_proto::product::product_service_client::ProductServiceClient; pub struct OrderServiceImpl { user_client: UserServiceClient, product_client: ProductServiceClient, } #[tonic::async_trait] impl OrderService for OrderServiceImpl { async fn create_order( &self, request: tonic::Request, ) -> Result, tonic::Status> { let req = request.into_inner(); // Вызвать User Service // Вызвать Product Service // Создать заказ Ok(tonic::Response::new(Order { id: 1, user_id: req.user_id, product_id: req.product_id, })) } } #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt::init(); let user_channel = Channel::from_static("http://127.0.0.1:13001") .connect() .await?; let product_channel = Channel::from_static("http://127.0.0.1:13002") .connect() .await?; let user_client = UserServiceClient::new(user_channel); let product_client = ProductServiceClient::new(product_channel); let order_service = OrderServiceImpl { user_client, product_client, }; let addr = "127.0.0.1:13003".parse()?; tracing::info!("Order Service listening on {}", addr); tonic::transport::Server::builder() .add_service(OrderServiceServer::new(order_service)) .serve(addr) .await?; Ok(()) } ``` ## 🔄 Интеграция с API Gateway После создания сервиса, обновите `api_gateway/src/main.rs` для добавления REST endpoints: ```rust // Создать gRPC клиента для вашего сервиса let my_service_channel = Channel::from_static("http://127.0.0.1:13002") .connect() .await?; // Добавить REST endpoints .route("/api/data/:id", get(get_data_handler)) ``` ## ✅ Чек-лист - [ ] Скопирован шаблон сервиса - [ ] Выбран порт (13000-14000) - [ ] Создан proto файл - [ ] Обновлен `shared_proto/src/lib.rs` - [ ] Обновлен `shared_proto/build.rs` - [ ] Обновлен `Cargo.toml` микросервиса - [ ] Реализована логика сервиса - [ ] Добавлен в workspace `Cargo.toml` - [ ] Успешно компилируется (`cargo check`) - [ ] Добавлены тесты (опционально) ## 🐛 Отладка ### Проверить что сервис запускается ```bash cargo run -p my_new_service ``` Должно вывести: ``` MyService gRPC server listening on 127.0.0.1:13002 ``` ### Проверить gRPC endpoint ```bash # Установить grpcurl если не установлен # https://github.com/fullstorydev/grpcurl grpcurl -plaintext localhost:13002 list ``` ### Логирование ```bash RUST_LOG=debug cargo run -p my_new_service ``` ## 📞 Помощь Если возникли проблемы: 1. Проверьте что все proto файлы скомпилировались 2. Убедитесь что порт не занят другим процессом 3. Проверьте логи сервиса 4. Обратитесь к `ARCHITECTURE.md` для общей информации