{"id":362381,"date":"2024-05-21T01:33:56","date_gmt":"2024-05-21T01:33:56","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=362381"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=362381","title":{"rendered":"<span>\u041a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c gRPC \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 Ruby \u0438 Go<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b48\/ea7\/b35\/b48ea7b35c964421a87031c8d4beb8a2.png\" width=\"1600\" height=\"902\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b48\/ea7\/b35\/b48ea7b35c964421a87031c8d4beb8a2.png\"\/><\/figure>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043b\u0438\u0447\u043d\u044b\u043c \u043e\u043f\u044b\u0442\u043e\u043c, \u043a\u0430\u043a \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 Ruby \u0438 Go \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 gRPC. \u041c\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u0445 gRPC;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u0445 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u043e \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a.<\/p>\n<\/li>\n<\/ul>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/h2>\n<p><a href=\"#1\">\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 gRPC?<\/a><\/p>\n<p><a href=\"#2\">gRPC \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#21\">\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 gRPC \u0434\u043b\u044f Ruby \u0438 Go<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#22\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 proto-\u0444\u0430\u0439\u043b\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#23\">\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#24\">\u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/a><\/p>\n<\/li>\n<\/ul>\n<p><a href=\"#3\">\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 gRPC<\/a><\/p>\n<p><a href=\"#4\">\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433\u0438<\/a><\/p>\n<h2>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 gRPC?<\/h2>\n<p><a class=\"anchor\" name=\"1\" id=\"1\"><\/a><\/p>\n<p>gRPC &#8212; \u044d\u0442\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0430<a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A3%D0%B4%D0%B0%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D1%8B%D0%B7%D0%BE%D0%B2_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D0%B4%D1%83%D1%80\"> <\/a>\u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 &#8212; \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u0433\u0434\u0435 \u044d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u043c \u043e\u0431\u043c\u0435\u043d\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438.\u00a0<\/p>\n<p>GRPC \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ul>\n<li>\n<p>\u041b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u043e\u0441\u0442\u044c \u0438 \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f: \u0448\u0430\u0431\u043b\u043e\u043d \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 proto-\u0444\u0430\u0439\u043b\u0430 (\u0435\u0433\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 protocol buffer \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430)<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445, \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0438 \u0434\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432<\/p>\n<\/li>\n<\/ul>\n<h2>gRPC \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435<\/h2>\n<p><a class=\"anchor\" name=\"2\" id=\"2\"><\/a><\/p>\n<p>\u041d\u0430\u0448 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f gRPC &#8212; \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u043e\u0432\u0430\u0440\u0430\u0445 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435. \u0421\u0435\u0440\u0432\u0435\u0440 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Ruby, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043c\u043e\u0434\u0443\u043b\u044c, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 Go.<\/p>\n<h3>1. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 gRPC \u0434\u043b\u044f Ruby \u0438 Go<\/h3>\n<p><a class=\"anchor\" name=\"21\" id=\"21\"><\/a><\/p>\n<p>\u0414\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 Ruby \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/github.com\/bigcommerce\/gruf\"><u>gruf<\/u><\/a> &#8212; \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0449\u0438\u0435 \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0443\u0436\u0431\u044b gRPC \u0432 Ruby.<\/p>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Go \u0431\u044b\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0442\u0430\u043a\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u0430\u043a <a href=\"https:\/\/pkg.go.dev\/github.com\/golang\/protobuf\/protoc-gen-go\"><u>protoc-gen-go<\/u><\/a>,\u00a0 \u043f\u043b\u0430\u0433\u0438\u043d \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430 Go \u0438 <a href=\"https:\/\/pkg.go.dev\/google.golang.org\/grpc\/cmd\/protoc-gen-go-grpc\"><u>protoc-gen-go-grpc<\/u><\/a>.<\/p>\n<h3>2. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 proto-\u0444\u0430\u0439\u043b\u0430<\/h3>\n<p><a class=\"anchor\" name=\"22\" id=\"22\"><\/a><\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 gRPC \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0430\u043c\u043e\u0433\u043e proto-\u0444\u0430\u0439\u043b\u0430.\u00a0 \u0412 \u043d\u0451\u043c\u00a0 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438\u043b\u0438 \u0441\u043b\u0443\u0436\u0431\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0442\u0438\u043f\u044b \u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432.\u00a0 Proto-\u0444\u0430\u0439\u043b\u044b \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c\u00a0 \u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b products.proto \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>syntax = \"proto3\";  package rpc; option go_package = \".\/products\"; \/\/ \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f Go  \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 service Products {     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430     rpc GetProduct(GetProductReq) returns (GetProductResp) {}     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432     rpc GetProducts(GetProductsReq) returns (stream Product) {}     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432     rpc CreateProducts(stream Product) returns (CreateProductsResp) {}     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432     rpc CreateProductsInStream(stream Product) returns (stream Product) {} }  \/\/ \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 message Product {     uint32 id = 1;     string name = 2;     float price = 3; }  message GetProductReq {     uint32 id = 1; }  message GetProductResp {     Product product = 1; }  message GetProductsReq {     string search = 1;     uint32 limit = 2; }  message CreateProductsResp {     repeated Product products = 1; }  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0441\u0442\u044c 4 \u0442\u0438\u043f\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432 gRPC:<\/p>\n<p>1. \u041f\u0440\u043e\u0441\u0442\u043e\u0439 RPC, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 \u0438 \u0436\u0434\u0451\u0442 \u043e\u0442\u0432\u0435\u0442\u0430, \u043a\u0430\u043a \u043f\u0440\u0438 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc GetProduct(GetProductReq) returns (GetProductResp) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5b9\/fd4\/c0c\/5b9fd4c0c2b6c55fc5905870b2de22a3.png\" width=\"922\" height=\"305\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5b9\/fd4\/c0c\/5b9fd4c0c2b6c55fc5905870b2de22a3.png\"\/><\/figure>\n<p>2. RPC \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u0447\u0442\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041a\u043b\u0438\u0435\u043d\u0442 \u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0437 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043a\u043e\u043d\u0447\u0430\u0442\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc GetProducts(GetProductsReq) returns (stream Product) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fa3\/5e4\/9f3\/fa35e49f3a1441fb623a25e91e4538d6.png\" width=\"922\" height=\"305\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fa3\/5e4\/9f3\/fa35e49f3a1441fb623a25e91e4538d6.png\"\/><\/figure>\n<p>3. RPC \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0441\u043d\u043e\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u043d \u0436\u0434\u0451\u0442, \u043f\u043e\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0445 \u0432\u0441\u0435 \u0438 \u0432\u0435\u0440\u043d\u0451\u0442 \u0441\u0432\u043e\u0439 \u043e\u0442\u0432\u0435\u0442. <\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc CreateProducts(stream Product) returns (CreateProductsResp) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1f6\/398\/9fc\/1f63989fcfe40dcc4c793056e5d9267a.png\" width=\"992\" height=\"313\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1f6\/398\/9fc\/1f63989fcfe40dcc4c793056e5d9267a.png\"\/><\/figure>\n<p>4. \u0414\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 RPC, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u0431\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u043e\u0442\u043e\u043a \u0447\u0442\u0435\u043d\u0438\u044f-\u0437\u0430\u043f\u0438\u0441\u0438. \u0414\u0432\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0433\u0443\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043b\u044e\u0431\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435:<\/p>\n<ul>\n<li>\n<p>\u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u0434\u043e\u0436\u0434\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0442\u0432\u0435\u0442\u044b<\/p>\n<\/li>\n<li>\n<p>\u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043e\u0447\u0435\u0440\u0451\u0434\u043d\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0430 \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0445. \u041e\u0442\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc CreateProductsInStream(stream Product) returns (stream Product) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c57\/be6\/16a\/c57be616a3a1e8125aec82f3cbe560d3.png\" width=\"889\" height=\"284\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c57\/be6\/16a\/c57be616a3a1e8125aec82f3cbe560d3.png\"\/><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a proto-\u0444\u0430\u0439\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0432\u0435\u0441\u0442\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<blockquote>\n<p><em>protoc -I .\/ &#8212;go_out=. &#8212;go_opt=paths=source_relative \\<\/em><\/p>\n<p><em>&#8212;go-grpc_out=. &#8212;go-grpc_opt=paths=source_relative \\<\/em><\/p>\n<p><em>*.proto<\/em><\/p>\n<\/blockquote>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u043d\u0435\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 proto-\u0444\u0430\u0439\u043b\u0430:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3a9\/c58\/624\/3a9c58624560d58eb89e365f1767a60d.png\" width=\"213\" height=\"96\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3a9\/c58\/624\/3a9c58624560d58eb89e365f1767a60d.png\"\/><\/figure>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1c8\/2cc\/14b\/1c82cc14b9464870772942e81dbc623a.png\" width=\"243\" height=\"123\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1c8\/2cc\/14b\/1c82cc14b9464870772942e81dbc623a.png\"\/><\/figure>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442:<\/p>\n<ul>\n<li>\n<p>\u0432\u0435\u0441\u044c protocol buffer \u043a\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f, \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043e\u0442\u0432\u0435\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u0442\u0438\u043f\u044b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438\u043b\u0438 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 Products \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0442\u0438\u043f\u044b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 Products \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438<\/p>\n<\/li>\n<\/ul>\n<h3>3. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/h3>\n<p><a class=\"anchor\" name=\"23\" id=\"23\"><\/a><\/p>\n<p>\u041d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043c\u043e\u0434\u0435\u043b\u044c \u0438 Enumerator-\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u0430 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c Product \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"># frozen_string_literal: true  class Product &lt; ApplicationRecord   validates_presence_of :name    scope :with_name, ->(name) { where(name: name) }    ##   # @return [Rpc::Product]   #   def to_proto Rpc::Product.new(   id: id.to_i,   name: name.to_s,   price: price.to_f )   end end  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>Enumerator \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"># frozen_string_literal: true  module Rpc   class ProductRequestEnumerator def initialize(products, delay = 0.5)     @products = products     @delay = delay.to_f end  def each_item     return enum_for(:each_item) unless block_given?      @products.each do |product|         sleep @delay         puts \"Next product to send is #{product.inspect}\"         yield product     end end   end end<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>Enumerator \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"># frozen_string_literal: true  module Rpc   class ProductResponseEnumerator def initialize(products, created_products, delay = 0.5)     @products = products     @created_products = created_products     @delay = delay.to_f end  def each_item     Rails.logger.info 'got to ProductResponseEnumerator.each_item'     return enum_for(:each_item) unless block_given?    begin       @products.each do |req|          earlier_requests = @created_products[req.name]          @created_products[req.name] &lt;&lt; req          Rails.logger.info \"Got request: #{req.inspect}\"           earlier_requests.each do |r|         product = Product.new(name: r.name, price: r.price).to_proto         sleep @delay         Rails.logger.info \"Sending back to client: #{product.inspect}\"         yield product          end       end   rescue StandardError => e       raise e # signal completion via an error   end     end   end end<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u044b, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0432 proto-\u0444\u0430\u0439\u043b\u0435, \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043e\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438).\u00a0<\/p>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430:<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Ruby-\u0441\u0435\u0440\u0432\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\">def get_product    product = ::Product.find(request.message.id.to_i)     Rpc::GetProductResp.new(      product: Rpc::Product.new(        id: product.id.to_i,        name: product.name.to_s,        price: product.price.to_f      )    )  rescue ::ActiveRecord::RecordNotFound => _e    fail!(:not_found, :product_not_found, \"Failed to find Product with ID: #{request.message.id}\")  rescue StandardError => e    set_debug_info(e.message, e.backtrace[0..4])    fail!(:internal, :internal, \"ERROR: #{e.message}\")  end<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Go-\u043a\u043b\u0438\u0435\u043d\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func GetProduct(client products.ProductsClient, id uint32) (*products.GetProductResp, error) {     product, err := client.GetProduct(context.Background(), &amp;products.GetProductReq{Id: id})     if err != nil {      log.Printf(\"failed to get product: %v\", err)      return product, err      }     return product, nil  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432:<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Ruby-\u0441\u0435\u0440\u0432\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\">def get_products    return enum_for(:get_products) unless block_given?     q = ::Product    q = q.where('name LIKE ?', \"%#{request.message.search}%\") if request.message.search.present?    limit = request.message.limit.to_i.positive? ? request.message.limit : 100    q.limit(limit).each do |product|      yield product.to_proto    end  rescue StandardError => e    set_debug_info(e.message, e.backtrace[0..4])    fail!(:internal, :internal, \"ERROR: #{e.message}\")  end <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Go-\u043a\u043b\u0438\u0435\u043d\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func GetProducts(client products.ProductsClient, search string, limit uint32) ([]*products.Product, error) {       productList, err := client.GetProducts(context.Background(), &amp;products.GetProductsReq{Search: search, Limit: limit})     if err != nil {      log.Printf(\"failed to get book list: %v\", err)      return nil, err     }   prods := make([]*products.Product, 0)     for {     product, err := productList.Recv()     if err == io.EOF {     break     }     if err != nil {     log.Printf(\"failed to get product: %v\", err)     return nil, err     }     prods = append(prods, product)     }       return prods, nil }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430:<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Ruby-\u0441\u0435\u0440\u0432\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"> def create_products    products = []    request.messages do |message|      products &lt;&lt; Product.create(name: message.name, price: message.price).to_proto    end    Rpc::CreateProductsResp.new(products: products)  rescue StandardError => e    set_debug_info(e.message, e.backtrace[0..4])    fail!(:internal, :internal, \"ERROR: #{e.message}\")  end  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Go-\u043a\u043b\u0438\u0435\u043d\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func CreateProducts(client products.ProductsClient, product_list []*products.Product) (*products.CreateProductsResp, error) {     stream, err := client.CreateProducts(context.Background())     if err != nil {      log.Printf(\"%v.CreateProducts(_) = _, %v\", client, err)         return nil, err     }      for _, product := range product_list {     if err := stream.Send(product); err != nil {     log.Printf(\"%v.Send(%v) = %v\", stream, product_list, err)      return nil, err     }     }      productList, err := stream.CloseAndRecv()     if err != nil {      log.Printf(\"failed to create product list: %v\", err)     return productList, err     }   return productList, nil }  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432:<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Ruby-\u0441\u0435\u0440\u0432\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\">def create_products_in_stream    return enum_for(:create_products_in_stream) unless block_given?     request.messages.each do |r|      sleep(rand(0.01..0.3))      yield Product.new(name: r.name, price: r.price).to_proto    rescue StandardError => e      set_debug_info(e.message, e.backtrace[0..4])      fail!(:internal, :internal, \"ERROR: #{e.message}\")    end  end <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Go-\u043a\u043b\u0438\u0435\u043d\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func CreateProductsInStream(client products.ProductsClient, product_list []*products.Product) ([]*products.Product, error) {     stream, err := client.CreateProducts(context.Background())     if err != nil {     log.Printf(\"%v.CreateProducts(_) = _, %v\", client, err)     return nil, err     }     prods := make([]*products.Product, 0)     for {     prductsList, err := stream.Recv()     if err == io.EOF {       return nil, err     }     if err != nil {       return nil, err     }      for _, product := range prductsList {       if err := stream.Send(product); err != nil {     return nil, err       }       prods = append(prods, product)     }         }      return prods, nil  } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h3>4. \u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h3>\n<p><a class=\"anchor\" name=\"24\" id=\"24\"><\/a><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.\u00a0<\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"># frozen_string_literal: true require_relative 'config\/application'   cli = Gruf::Cli::Executor.new cli.run<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func main() {    err := godotenv.Load()    if err != nil {        log.Fatalf(\"err loading: %v\", err)    }    conn, err := grpc.Dial(os.Getenv(\"SERVER_HOST\"), grpc.WithTransportCredentials(insecure.NewCredentials()))    if err != nil {        log.Fatalf(\"failed to connect: %v\", err)    }    defer conn.Close()    \/\/ \u0412\u044b\u0437\u043e\u0432 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u043d\u0430\u0448\u0438\u043c\u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/36e\/8d8\/d76\/36e8d8d7671090b031ced9e9df88ca80.png\" width=\"563\" height=\"407\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/36e\/8d8\/d76\/36e8d8d7671090b031ced9e9df88ca80.png\"\/><\/figure>\n<p>\u0412\u043e\u0442 \u0438 \u0432\u0441\u0451, gRPC \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d!<\/p>\n<h2>\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 gRPC<\/h2>\n<p><a class=\"anchor\" name=\"3\" id=\"3\"><\/a><\/p>\n<p>\u0415\u0441\u0442\u044c \u0440\u044f\u0434 \u043d\u044e\u0430\u043d\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u0447\u0435\u0441\u0442\u044c \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 gRPC. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0443\u043b\u0435\u0432\u044b\u043c\u0438 \u2014 \u043e\u043d\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u043c\u0435\u044e\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0412\u0441\u0451, \u0447\u0442\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f, \u043f\u0440\u0438\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u043c\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0432 \u0446\u0435\u043b\u044f\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0440\u0430\u043d\u0441\u0444\u0435\u0440\u0430. \u042d\u0442\u043e \u0437\u0430\u0442\u0440\u0443\u0434\u043d\u044f\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439.\u00a0<\/p>\n<p>\u041d\u0435\u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u043e\u0433\u0443\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0442\u044c \u043f\u0440\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0438 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 XML \u0438 JSON, \u0444\u0430\u0439\u043b\u044b Protobuf \u043d\u0435 \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e\u043c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0436\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0434\u043e \u0434\u0432\u043e\u0438\u0447\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430. \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u043e\u0446\u0435\u043d\u043a\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043d\u0435\u043f\u043e\u043b\u0430\u0434\u043e\u043a \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0443\u0447\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<h2>\u041f\u043e\u0434\u0432\u0435\u0434\u0451\u043c \u0438\u0442\u043e\u0433\u0438<\/h2>\n<p><a class=\"anchor\" name=\"4\" id=\"4\"><\/a><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0449\u0435\u0442\u0435 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u0432\u0430\u0448\u0438\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u0442\u043e gRPC \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0441 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u044d\u0442\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441 \u0440\u044f\u0434\u043e\u043c \u0441\u0432\u043e\u0438\u0445 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439, \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0432\u0430\u043c \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u043e\u0431\u043c\u0435\u043d \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u0437\u0430 \u0441\u0447\u0451\u0442 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430 .proto, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u0443 \u0434\u043b\u044f \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0441\u0432\u044f\u0437\u0438 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/779272\/\"> https:\/\/habr.com\/ru\/articles\/779272\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043b\u0438\u0447\u043d\u044b\u043c \u043e\u043f\u044b\u0442\u043e\u043c, \u043a\u0430\u043a \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 Ruby \u0438 Go \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 gRPC. \u041c\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u0445 gRPC;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u0445 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u043e \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a.<\/p>\n<\/li>\n<\/ul>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/h2>\n<p><a href=\"#1\">\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 gRPC?<\/a><\/p>\n<p><a href=\"#2\">gRPC \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435<\/a><\/p>\n<ul>\n<li>\n<p><a href=\"#21\">\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 gRPC \u0434\u043b\u044f Ruby \u0438 Go<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#22\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 proto-\u0444\u0430\u0439\u043b\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#23\">\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#24\">\u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/a><\/p>\n<\/li>\n<\/ul>\n<p><a href=\"#3\">\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 gRPC<\/a><\/p>\n<p><a href=\"#4\">\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433\u0438<\/a><\/p>\n<h2>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 gRPC?<\/h2>\n<p><a class=\"anchor\" name=\"1\" id=\"1\"><\/a><\/p>\n<p>gRPC &#8212; \u044d\u0442\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0430<a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A3%D0%B4%D0%B0%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B2%D1%8B%D0%B7%D0%BE%D0%B2_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D0%B4%D1%83%D1%80\"> <\/a>\u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 &#8212; \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u0433\u0434\u0435 \u044d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u043c \u043e\u0431\u043c\u0435\u043d\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438.\u00a0<\/p>\n<p>GRPC \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ul>\n<li>\n<p>\u041b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u043e\u0441\u0442\u044c \u0438 \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f: \u0448\u0430\u0431\u043b\u043e\u043d \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 proto-\u0444\u0430\u0439\u043b\u0430 (\u0435\u0433\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 protocol buffer \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430)<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445, \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0438 \u0434\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432<\/p>\n<\/li>\n<\/ul>\n<h2>gRPC \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435<\/h2>\n<p><a class=\"anchor\" name=\"2\" id=\"2\"><\/a><\/p>\n<p>\u041d\u0430\u0448 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f gRPC &#8212; \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u043e\u0432\u0430\u0440\u0430\u0445 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435. \u0421\u0435\u0440\u0432\u0435\u0440 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Ruby, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043c\u043e\u0434\u0443\u043b\u044c, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 Go.<\/p>\n<h3>1. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 gRPC \u0434\u043b\u044f Ruby \u0438 Go<\/h3>\n<p><a class=\"anchor\" name=\"21\" id=\"21\"><\/a><\/p>\n<p>\u0414\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 Ruby \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/github.com\/bigcommerce\/gruf\"><u>gruf<\/u><\/a> &#8212; \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0449\u0438\u0435 \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0443\u0436\u0431\u044b gRPC \u0432 Ruby.<\/p>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Go \u0431\u044b\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0442\u0430\u043a\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u0430\u043a <a href=\"https:\/\/pkg.go.dev\/github.com\/golang\/protobuf\/protoc-gen-go\"><u>protoc-gen-go<\/u><\/a>,\u00a0 \u043f\u043b\u0430\u0433\u0438\u043d \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430 Go \u0438 <a href=\"https:\/\/pkg.go.dev\/google.golang.org\/grpc\/cmd\/protoc-gen-go-grpc\"><u>protoc-gen-go-grpc<\/u><\/a>.<\/p>\n<h3>2. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 proto-\u0444\u0430\u0439\u043b\u0430<\/h3>\n<p><a class=\"anchor\" name=\"22\" id=\"22\"><\/a><\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 gRPC \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0430\u043c\u043e\u0433\u043e proto-\u0444\u0430\u0439\u043b\u0430.\u00a0 \u0412 \u043d\u0451\u043c\u00a0 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438\u043b\u0438 \u0441\u043b\u0443\u0436\u0431\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0442\u0438\u043f\u044b \u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432.\u00a0 Proto-\u0444\u0430\u0439\u043b\u044b \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c\u00a0 \u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b products.proto \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>syntax = \"proto3\";  package rpc; option go_package = \".\/products\"; \/\/ \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f Go  \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 service Products {     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430     rpc GetProduct(GetProductReq) returns (GetProductResp) {}     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432     rpc GetProducts(GetProductsReq) returns (stream Product) {}     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432     rpc CreateProducts(stream Product) returns (CreateProductsResp) {}     \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432     rpc CreateProductsInStream(stream Product) returns (stream Product) {} }  \/\/ \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 message Product {     uint32 id = 1;     string name = 2;     float price = 3; }  message GetProductReq {     uint32 id = 1; }  message GetProductResp {     Product product = 1; }  message GetProductsReq {     string search = 1;     uint32 limit = 2; }  message CreateProductsResp {     repeated Product products = 1; }  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0441\u0442\u044c 4 \u0442\u0438\u043f\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432 gRPC:<\/p>\n<p>1. \u041f\u0440\u043e\u0441\u0442\u043e\u0439 RPC, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 \u0438 \u0436\u0434\u0451\u0442 \u043e\u0442\u0432\u0435\u0442\u0430, \u043a\u0430\u043a \u043f\u0440\u0438 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc GetProduct(GetProductReq) returns (GetProductResp) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><\/figure>\n<p>2. RPC \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u0447\u0442\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041a\u043b\u0438\u0435\u043d\u0442 \u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0437 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043a\u043e\u043d\u0447\u0430\u0442\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc GetProducts(GetProductsReq) returns (stream Product) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><\/figure>\n<p>3. RPC \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0441\u043d\u043e\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u043d \u0436\u0434\u0451\u0442, \u043f\u043e\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0445 \u0432\u0441\u0435 \u0438 \u0432\u0435\u0440\u043d\u0451\u0442 \u0441\u0432\u043e\u0439 \u043e\u0442\u0432\u0435\u0442. <\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc CreateProducts(stream Product) returns (CreateProductsResp) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><\/figure>\n<p>4. \u0414\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 RPC, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u0431\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u043e\u0442\u043e\u043a \u0447\u0442\u0435\u043d\u0438\u044f-\u0437\u0430\u043f\u0438\u0441\u0438. \u0414\u0432\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0433\u0443\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043b\u044e\u0431\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435:<\/p>\n<ul>\n<li>\n<p>\u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u0434\u043e\u0436\u0434\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0442\u0432\u0435\u0442\u044b<\/p>\n<\/li>\n<li>\n<p>\u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043e\u0447\u0435\u0440\u0451\u0434\u043d\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0430 \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0445. \u041e\u0442\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434 (protobuf)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>rpc CreateProductsInStream(stream Product) returns (stream Product) {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a proto-\u0444\u0430\u0439\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0432\u0435\u0441\u0442\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<blockquote>\n<p><em>protoc -I .\/ &#8212;go_out=. &#8212;go_opt=paths=source_relative \\<\/em><\/p>\n<p><em>&#8212;go-grpc_out=. &#8212;go-grpc_opt=paths=source_relative \\<\/em><\/p>\n<p><em>*.proto<\/em><\/p>\n<\/blockquote>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u043d\u0435\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 proto-\u0444\u0430\u0439\u043b\u0430:<\/p>\n<figure class=\"\"><\/figure>\n<figure class=\"\"><\/figure>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442:<\/p>\n<ul>\n<li>\n<p>\u0432\u0435\u0441\u044c protocol buffer \u043a\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f, \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043e\u0442\u0432\u0435\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u0442\u0438\u043f\u044b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438\u043b\u0438 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 Products \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0442\u0438\u043f\u044b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 Products \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438<\/p>\n<\/li>\n<\/ul>\n<h3>3. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/h3>\n<p><a class=\"anchor\" name=\"23\" id=\"23\"><\/a><\/p>\n<p>\u041d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043c\u043e\u0434\u0435\u043b\u044c \u0438 Enumerator-\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u0430 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c Product \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"># frozen_string_literal: true  class Product &lt; ApplicationRecord   validates_presence_of :name    scope :with_name, ->(name) { where(name: name) }    ##   # @return [Rpc::Product]   #   def to_proto Rpc::Product.new(   id: id.to_i,   name: name.to_s,   price: price.to_f )   end end  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>Enumerator \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"># frozen_string_literal: true  module Rpc   class ProductRequestEnumerator def initialize(products, delay = 0.5)     @products = products     @delay = delay.to_f end  def each_item     return enum_for(:each_item) unless block_given?      @products.each do |product|         sleep @delay         puts \"Next product to send is #{product.inspect}\"         yield product     end end   end end<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>Enumerator \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0434<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"># frozen_string_literal: true  module Rpc   class ProductResponseEnumerator def initialize(products, created_products, delay = 0.5)     @products = products     @created_products = created_products     @delay = delay.to_f end  def each_item     Rails.logger.info 'got to ProductResponseEnumerator.each_item'     return enum_for(:each_item) unless block_given?    begin       @products.each do |req|          earlier_requests = @created_products[req.name]          @created_products[req.name] &lt;&lt; req          Rails.logger.info \"Got request: #{req.inspect}\"           earlier_requests.each do |r|         product = Product.new(name: r.name, price: r.price).to_proto         sleep @delay         Rails.logger.info \"Sending back to client: #{product.inspect}\"         yield product          end       end   rescue StandardError => e       raise e # signal completion via an error   end     end   end end<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u044b, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0432 proto-\u0444\u0430\u0439\u043b\u0435, \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043e\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438).\u00a0<\/p>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430:<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Ruby-\u0441\u0435\u0440\u0432\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\">def get_product    product = ::Product.find(request.message.id.to_i)     Rpc::GetProductResp.new(      product: Rpc::Product.new(        id: product.id.to_i,        name: product.name.to_s,        price: product.price.to_f      )    )  rescue ::ActiveRecord::RecordNotFound => _e    fail!(:not_found, :product_not_found, \"Failed to find Product with ID: #{request.message.id}\")  rescue StandardError => e    set_debug_info(e.message, e.backtrace[0..4])    fail!(:internal, :internal, \"ERROR: #{e.message}\")  end<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Go-\u043a\u043b\u0438\u0435\u043d\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func GetProduct(client products.ProductsClient, id uint32) (*products.GetProductResp, error) {     product, err := client.GetProduct(context.Background(), &amp;products.GetProductReq{Id: id})     if err != nil {      log.Printf(\"failed to get product: %v\", err)      return product, err      }     return product, nil  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432:<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Ruby-\u0441\u0435\u0440\u0432\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\">def get_products    return enum_for(:get_products) unless block_given?     q = ::Product    q = q.where('name LIKE ?', \"%#{request.message.search}%\") if request.message.search.present?    limit = request.message.limit.to_i.positive? ? request.message.limit : 100    q.limit(limit).each do |product|      yield product.to_proto    end  rescue StandardError => e    set_debug_info(e.message, e.backtrace[0..4])    fail!(:internal, :internal, \"ERROR: #{e.message}\")  end <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Go-\u043a\u043b\u0438\u0435\u043d\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func GetProducts(client products.ProductsClient, search string, limit uint32) ([]*products.Product, error) {       productList, err := client.GetProducts(context.Background(), &amp;products.GetProductsReq{Search: search, Limit: limit})     if err != nil {      log.Printf(\"failed to get book list: %v\", err)      return nil, err     }   prods := make([]*products.Product, 0)     for {     product, err := productList.Recv()     if err == io.EOF {     break     }     if err != nil {     log.Printf(\"failed to get product: %v\", err)     return nil, err     }     prods = append(prods, product)     }       return prods, nil }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430:<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Ruby-\u0441\u0435\u0440\u0432\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"ruby\"> def create_products    products = []    request.messages do |message|      products &lt;&lt; Product.create(name: message.name, price: message.price).to_proto    end    Rpc::CreateProductsResp.new(products: products)  rescue StandardError => e    set_debug_info(e.message, e.backtrace[0..4])    fail!(:internal, :internal, \"ERROR: #{e.message}\")  end  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Go-\u043a\u043b\u0438\u0435\u043d\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">func CreateProducts(client products.ProductsClient, product_list []*products.Product) (*products.CreateProductsResp, error) {     stream, err := client.CreateProducts(context.Background())     if err != nil {      log.Printf(\"%v.CreateProducts(_) = _, %v\", client, err)         return nil, err     }      for _, product := range product_list {     if err := stream.Send(product); err != nil {     log.Printf(\"%v.Send(%v) = %v\", stream, product_list, err)      return nil, <\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-362381","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/362381","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=362381"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/362381\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=362381"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=362381"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=362381"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}