-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an ability to run protobuf server as a Servlet 4 #1621
Comments
Dump from what I wrote on SO to have the information in one place:
|
Could someone please give a status update on this topic? Thanks! |
No progress. I still don't know how to send trailers in this environment. |
JavaDoc for Java EE 8 / Servlet 4.0 describes an API to set trailers on a response. |
@jnehlmeier, thank you! I'll note one part of the docs that could be an annoyance, but I think they are talking about the remote, not the servlet (in which case we're fine to ignore it):
If it is for servlet interoperability we can still live with it, but it requires the application to help us out. Go already has to deal with something similar when using the Go-provided http/2 server. |
@ejona86 can you elaborate what exactly you don't know how to do using servlets? I want to help implement this feature. Is not this what you are referring to?
If there is something specific that servlet is not doing for you lets discus explicitly and I'll help. Even if servlet spec does not allow to run gRPC server, we can still provide enough adapters so that it can run on top of jetty, undertow and tomcat. In that way at least servlets and gRPC can share the same port An example of what I mentioned was already in the works, see wildfly mailing list |
@hofmanndavid, I think it would be (relatively) easy to make a servlet that would handle the I/O for gRPC. Any questions remaining in my mind are mainly on the nicest way of configuring the thing. It would implement |
Okay, Will try to get back when I have something. give me 2 weeks. |
The "Trailer" in the headers is required by RFC7230 (HTTP/1.1) . So hopefully the "interoperability failure" will only occur for HTTP/1.1 clients, and HTTP/2 clients can still interoperate.
|
The "Trailer" header applies equally in HTTP/1.1 and HTTP/2. HTTP/2 didn't change those semantics. |
Quoting from the protocol doc
The initial problem I am seeing when trying to use a servlet container instead of netty is that netty owns the root path /* So. We are dealing with multiple applications running in a servlet container. eg. There is a rule for request mapping in servlets and is that the longest path that matches is the one used to route a request to the proper app. In case both apps will use grpc, and is what should be supported. This will happen:
For grpc to work in a servlet container the proper way to support it IMHO is to:
It would be desirable to have an optional parameter in the proto file that will trigger small client code generation for adding the prefix (maybe not optional if defined in the proto file) This will lower the entry barrier for grpc usage inside enterprises that rely a lot in application servers. Is the reasoning correct or is there a fundamental problem? |
@ejona86 you're right.
I read https://tools.ietf.org/html/rfc7230#section-4.4 again, it says "Trailer" header is required |
Yep. I was aware this was going to be a problem. I think it will remain a problem for the while. I'd like to focus on getting '/' webapps working first.
I don't think we'll have much of a problem here, since it's likely only the '/' app can serve gRPC. The paths involved almost always end in /, so the only case there could be a collision is if a web app wanted to be deployed at '/myproto.package.MyService/'.
This adds a complexity for all clients, which is really unfortunate. In my mind clients shouldn't need to know about this sort of thing. There are workarounds for Java that are a bit ugly, but functional. This is a bit of a touchy subject.
This isn't bad, although I question how it would work in practice. It only works when there will be a single implementation of a service. If you think about something like our reflection and monitoring services, this sort of solution wouldn't function. |
A possible workaround (without client adding prefix):
|
@hofmanndavid Have you been actively making progress on it? Would you mind if I pick it up? Just in case a competing implementation may make you uncomfortable if you had something already.
|
@dapengzhang0 I am utterly sorry I could not make any progress in this part yet. |
@dapengzhang0 I don't see how a ServletFilter will work as it works inside an already defined context path (e.g. Basically anything that does not involve the client adding the deployed application context path will involve a server-specific configuration. |
@hofmanndavid By calling ServletContext.getContext(String uripath) you can get even another web application's servletContext as long as both apps are deployed in the same container.
|
@dapengzhang0 I didn't know you can get other contexts on the same server. But still, in your example |
@hofmanndavid Yes, you need at least to deploy the filter at /GreetService. In the case both /app1 and /app2 have implementation logic of greeter service, the filter could forward requests to /app1 or /app2 depending additional custom header in the original request. If you can not deploy anything to /GreetService or /*, then of course you can not handle regular grpc requests. |
@cs224 I'm currently working on this. I'd really like to hear from users, how would you like the API to look like.
|
@dapengzhang0
This seems to work pretty well. Can you tell us how the current progress of this project? Do you think the servlet implementation is going to be included in the grpc-java standard? Thank you very much for your effort. |
@RaphaelKellerAdc Thank you for your feedback! The current status of this project is (1) collecting feedback from potential users, (2) adding test code, (3) writing documentation. Once they are done, the servlet implementation will be part of grpc-java library in a separate package For your usecase with interceptors, would it help to add a constructor of /**
* Instantiate the servlet with the given serverBuilder.
*/
public GrpcServlet(ServletServerBuilder serverBuilder) {
servletAdapter = ServletAdapter.Factory.create(serverBuilder);
} |
Ok, I am just trying to test that an HelloWorld works on Wildfly, testing with 17.0.1.Final. And is seems to be working but I get this error when I deploy a simple servlet extending GrpcServlet:
Exception:
I have not dug deeper into it, as the client call works for both sync and async case. Using the example servlet from the tree, that inherits from HttpServlet does not generate this error. Is this expected or does the class miss a default constructor? |
@lastcmaster Thanks for trying it out. I don't see any essential difference between your servlet and the example servlet. Actually I'm trying to use an extension of I'm not familiar with WildFly. Did you config anything in |
My jboss-web.xml only contains the content root element: |
FWIW we were able to get it working in Jetty. Our servlet is pretty custom but it’s definitely possible. The only trick was for duplex streaming we needed this option:
|
@hofmanndavid , @dapengzhang0 , @ejona86 : I was left with a doubt, if I keep the root path only for my gRPC implementations, and the contexts for HTTP1 implementations, will I encounter problems? I am implementing tests using liberty, and websphere application server 9 on z / OS. Until next week I'll answer how we're doing. |
@rogeriob2br the grpc maintainers haven't given any updates on this issue in some time. There shouldn't be any problem keeping "the root path only for my gRPC implementations". WAS 9 isn't going to support this at all, since it doesn't provide an HTTP/2 implementation. Liberty partially supports #4738, but full duplex streaming isn't working. From the OpenLiberty side, we're working on new features to directly support grpc - see OpenLiberty/open-liberty#8637 |
I was focused on some other priorities. As there are more and more people interested in this feature, I will pickup it soon. Sorry for the delahy. |
If your application server supports both HTTP/2 and HTTP1 traffic, then it should work for grpc client to grpc path and normal HTTP/1 client to other path. |
:( |
@dapengzhang0 there's an error - but the problem is with Liberty's async behavior. We're working on a fix on that side. |
I've been working on this branch recently, and have it updated to latest grpc (as well as intermediate versions in case someone happens to need it backported), with all tests passing in undertow and jetty (see jetty/jetty.project#6917 for the ability to run this also in Jetty 9.4.x), and two failing in tomcat. Is there interest still in accepting this upstream, or should I explore options to release this directly when I reach some milestone? I'll soon be exploring #4823 as well and possibly a servlet based implementation of the websocket handling present in https://github.com/improbable-eng/grpc-web/tree/master/go/grpcweb for non-tls streaming browser connections, and would love any feedback on if that work belongs in the grpc-servlet project, or as an external component. I'm happy to have discussion take place either here or 4823 on this topic. |
@niloc132 If you want Servlet 4.0 behavior of Jetty 9.4.x is in maintenance mode now, only handling bug fixes and security fixes, not new functionality. Note that |
Thanks for taking a look here @joakime - as grpc-java builds with baseline support for Java 8, it can only conditionally run the integration tests if Java 11+ happens to be available. Separately, I'm investigating using eclipse's transformer tool to enable several projects I use to ease this migration. |
Why Java 8 still? Java 8 is scheduled to end it's "Premier Support" on March 2022 (6 months from now), going to "Extended Support" model until Dec 2030 at which point it will enter into the "Lifetime Support" mode. In my mind, this lack of public JVMs, makes Java 8 not a viable choice for open source projects that need/rely on SSL/TLS. (but we'll see what the world of OpenJDK 8 brings to the table in this regard) |
Don't waste your time, the upcoming Jakarta Servlet 6.0 (due out in the next couple of months) has already removed long deprecated classes and methods. |
Using Assume to skip certain tests on Java 8 is fine. No big deal. As it happens, we are still supporting Java 7. We hope to drop that "soon" (#4671). I've heard orphaned projects (including "v2 is a completely different API and v1 is now dead and I hope you like rewriting") have made it a "process" to upgrade, especially for things like application containers that can be picky about their JRE. That's a different sort of problem compared to Java 8 vs 11 where Java 11 is slower for some workloads (both JIT and GC can contribute). |
This has been merged in 706646f, with support for both javax and jakarta servlet apis. Jetty seems to have the best support, though jetty/jetty.project#8405 may cause errors for grpc streams that don't respond within 30s - I'll follow up soon with the workaround for this that we're using in production. Outside from that I'm still planning to continue with the notes in #4823 (comment) - landing an in-process grpc-web proxy, and hopefully other outright offering the websocket transport we use (compatible with https://github.com/improbable-eng/grpc-web/), or some simple changes to the ServletAdapter so that the ServerTransportListener, etc can be shared between multiple endpoints, which enables custom transports (use case being streaming data where tls isn't available, like localhost development). |
Pls add an ability to run a protobuf v3 server as a Servlet 4 on any server with the Servlet 4 support.
The text was updated successfully, but these errors were encountered: