-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
409a7ded.c459fdd7.js
1 lines (1 loc) · 10.9 KB
/
409a7ded.c459fdd7.js
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{119:function(e,n,t){"use strict";t.d(n,"a",(function(){return b})),t.d(n,"b",(function(){return g}));var r=t(0),a=t.n(r);function l(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function c(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){l(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=a.a.createContext({}),p=function(e){var n=a.a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},b=function(e){var n=p(e.components);return a.a.createElement(s.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return a.a.createElement(a.a.Fragment,{},n)}},d=a.a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),b=p(t),d=r,g=b["".concat(i,".").concat(d)]||b[d]||u[d]||l;return t?a.a.createElement(g,c(c({ref:n},s),{},{components:t})):a.a.createElement(g,c({ref:n},s))}));function g(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=d;var c={};for(var o in n)hasOwnProperty.call(n,o)&&(c[o]=n[o]);c.originalType=e,c.mdxType="string"==typeof e?e:r,i[1]=c;for(var s=2;s<l;s++)i[s]=t[s];return a.a.createElement.apply(null,i)}return a.a.createElement.apply(null,t)}d.displayName="MDXCreateElement"},88:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return c})),t.d(n,"metadata",(function(){return o})),t.d(n,"toc",(function(){return s})),t.d(n,"default",(function(){return b}));var r=t(3),a=t(7),l=(t(0),t(119)),i=["components"],c={title:"gRPC",layout:"docs"},o={unversionedId:"grpc",id:"grpc",isDocsHomePage:!1,title:"gRPC",description:"gRPC Libraries for ScalaPB",source:"@site/../docs/target/mdoc/grpc.md",slug:"/grpc",permalink:"/docs/grpc",version:"current",sidebar:"someSidebar",previous:{title:"Defining custom options",permalink:"/docs/user_defined_options"},next:{title:"Using ScalaPB with Scala.js",permalink:"/docs/scala.js"}},s=[{value:"gRPC Libraries for ScalaPB",id:"grpc-libraries-for-scalapb",children:[]},{value:"Project Setup",id:"project-setup",children:[]},{value:"Creating a service",id:"creating-a-service",children:[]},{value:"Using the client",id:"using-the-client",children:[]},{value:"Writing a server",id:"writing-a-server",children:[]},{value:"Streaming clients, streaming servers, bidi",id:"streaming-clients-streaming-servers-bidi",children:[]},{value:"grpc-netty issues",id:"grpc-netty-issues",children:[]}],p={toc:s};function b(e){var n=e.components,t=Object(a.a)(e,i);return Object(l.b)("wrapper",Object(r.a)({},p,t,{components:n,mdxType:"MDXLayout"}),Object(l.b)("h2",{id:"grpc-libraries-for-scalapb"},"gRPC Libraries for ScalaPB"),Object(l.b)("p",null,"This page covers ScalaPB's gRPC support. This support is a thin wrapper around\ngrpc-java, and provides you with an interface that is based on Scala's\nstandard library ",Object(l.b)("inlineCode",{parentName:"p"},"Future"),", while streaming is based on the Observer pattern."),Object(l.b)("p",null,"There are additional gRPC libraries built on top of ScalaPB that provide integration with other concurrency frameworks and effect systems:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("a",{parentName:"li",href:"https://scalapb.github.io/zio-grpc/"},"ZIO gRPC")," enables you to build gRPC\nservers and clients using ZIO."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("a",{parentName:"li",href:"https://github.com/typelevel/fs2-grpc"},"fs2-grpc")," provides gGRPC support for FS2 and Cats Effect."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("a",{parentName:"li",href:"https://doc.akka.io/docs/akka-grpc/current/index.html"},"Akka gRPC")," provides support for building streaming gRPC servers and clients on top of Akka Streams and Akka HTTP."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("a",{parentName:"li",href:"https://pekko.apache.org/docs/pekko-grpc/current/"},"Pekko gRPC")," provides support for building streaming gRPC servers and clients on top of Pekko Streams and Pekko HTTP."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("a",{parentName:"li",href:"https://github.com/davenverse/http4s-grpc"},"http4s-grpc")," enables you to build gRPC clients and servers with Cats Effect and FS2. It is implemented on top of http4s Ember and runs on JVM, Node.js, and Scala Native.")),Object(l.b)("h2",{id:"project-setup"},"Project Setup"),Object(l.b)("p",null,"Install ScalaPB as usual. Add the following to your ",Object(l.b)("inlineCode",{parentName:"p"},"build.sbt"),":"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre"},'libraryDependencies ++= Seq(\n "io.grpc" % "grpc-netty" % scalapb.compiler.Version.grpcJavaVersion,\n "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion\n)\n')),Object(l.b)("h2",{id:"creating-a-service"},"Creating a service"),Object(l.b)("p",null,"When you run ",Object(l.b)("inlineCode",{parentName:"p"},"sbt compile"),", ScalaPB will generate code for your servers. This\nincludes an asynchronous client, a blocking and a base trait you can extend to\nimplement the server side."),Object(l.b)("p",null,"For example, if your proto file in ",Object(l.b)("inlineCode",{parentName:"p"},"src/main/protobuf/hello.proto")," looks like\nthis:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-protobuf"},'syntax = "proto3";\n\npackage com.example.protos;\n\n// The greeting service definition.\nservice Greeter {\n // Sends a greeting\n rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n// The request message containing the user\'s name.\nmessage HelloRequest {\n string name = 1;\n}\n\n// The response message containing the greetings\nmessage HelloReply {\n string message = 1;\n}\n')),Object(l.b)("p",null,"The generated code will look like this (simplified and commented):"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-scala"},"object GreeterGrpc {\n\n // Base trait for an asynchronous client and server.\n trait Greeter extends AbstractService {\n def serviceCompanion = Greeter\n def sayHello(request: HelloRequest): Future[HelloReply]\n }\n\n object Greeter extends ServiceCompanion[Greeter] {\n def descriptor = ...\n }\n\n // Abstract trait for a blocking client:\n trait GreeterBlockingClient {\n def serviceCompanion = Greeter\n def sayHello(request: HelloRequest): HelloReply\n }\n\n // Concrete blocking client:\n class GreeterBlockingStub(channel, options) extends [...] with GreeterBlockingClient {\n // omitted\n }\n\n // Concrete asynchronous client:\n class GreeterStub(channel, options) extends io.grpc.stub.AbstractStub[GreeterStub](channel, options) with Greeter {\n // omitted\n }\n\n // Creates a new blocking client.\n def blockingStub(channel: io.grpc.Channel): GreeterBlockingStub = new GreeterBlockingStub(channel)\n\n // Creates a new asynchronous client.\n def stub(channel: io.grpc.Channel): GreeterStub = new GreeterStub(channel)\n}\n")),Object(l.b)("h2",{id:"using-the-client"},"Using the client"),Object(l.b)("p",null,"Creating a channel:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-scala"},'val channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build\nval request = HelloRequest(name = "World")\n')),Object(l.b)("p",null,"Blocking call:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-scala"},"val blockingStub = GreeterGrpc.blockingStub(channel)\nval reply: HelloReply = blockingStub.sayHello(request)\nprintln(reply)\n")),Object(l.b)("p",null,"Async call:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre"},"val stub = GreeterGrpc.stub(channel)\nval f: Future[HelloReply] = stub.sayHello(request)\nf onComplete println\n")),Object(l.b)("h2",{id:"writing-a-server"},"Writing a server"),Object(l.b)("p",null,"Implement the service:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-scala"},'private class GreeterImpl extends GreeterGrpc.Greeter {\n override def sayHello(req: HelloRequest) = {\n val reply = HelloReply(message = "Hello " + req.name)\n Future.successful(reply)\n }\n}\n')),Object(l.b)("p",null,"See\n",Object(l.b)("a",{parentName:"p",href:"https://github.com/xuwei-k/grpc-scala-sample/blob/master/grpc-scala/src/main/scala/io/grpc/examples/helloworld/HelloWorldServer.scala"},"complete example server")," here."),Object(l.b)("h2",{id:"streaming-clients-streaming-servers-bidi"},"Streaming clients, streaming servers, bidi"),Object(l.b)("p",null,"Scalapb-grpc supports both client and server streaming. The Scala API follows\nclosely the offical ",Object(l.b)("inlineCode",{parentName:"p"},"grpc-java")," API. Example project coming soon."),Object(l.b)("h2",{id:"grpc-netty-issues"},"grpc-netty issues"),Object(l.b)("p",null,"In certain situations (for example when you have a fat jar), you may see the\nfollowing exception:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre"},'Exception in thread "main" io.grpc.ManagedChannelProvider$ProviderNotFoundException: No functional server found. Try adding a dependency on the grpc-netty artifact\n')),Object(l.b)("p",null,"To work around this issue, try the following solutions:"),Object(l.b)("ol",null,Object(l.b)("li",{parentName:"ol"},"Create a ",Object(l.b)("inlineCode",{parentName:"li"},"NettyServer")," explicitly using ",Object(l.b)("inlineCode",{parentName:"li"},"io.grpc.netty.NettyServerBuilder"),".")),Object(l.b)("p",null,"Example:"),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-scala"},"NettyServerBuilder\n .forPort(9000)\n .keepAliveTime(500, TimeUnit.SECONDS)\n")),Object(l.b)("ol",{start:2},Object(l.b)("li",{parentName:"ol"},"If using SBT, try the following merge conflict strategy:")),Object(l.b)("pre",null,Object(l.b)("code",{parentName:"pre",className:"language-scala"},'assemblyMergeStrategy in assembly := {\n case x if x.contains("io.netty.versions.properties") => MergeStrategy.discard\n case x =>\n val oldStrategy = (assemblyMergeStrategy in assembly).value\n oldStrategy(x)\n}\n')))}b.isMDXComponent=!0}}]);