-
Notifications
You must be signed in to change notification settings - Fork 9
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
Explore API with decode/encode in the library (draft) #48
Conversation
Thank you for your interest in One thing that comes to mind is to define an interface for encoding/decoding and make use of functors or first-class modules to use a specific backend. It can be almost as ergonomic for the user while still keeping the library flexible. I believe your code can be used as a starting point for such an effort, in particular the interfaces you define in |
We could also embrace one of the plugins/transports as the de-facto workflow for ocaml grpc and release work such as presented here as ocaml-grpc-protobuf (for example) with a more opinionated interface. |
Hello, Thank you for your insightful feedback. In response to your comments, I've made additional modifications to the PR. I've Your feedback reminded me of this article on typing RPCs: https://blog.janestreet.com/typing-rpcs/ I appreciate the ongoing dialogue and am open to further discussions. If you Thank you once again for your time and consideration! |
Thank you, these changes look very good. Just one thing, I'd put as much of this as possible into the core |
- `Grpc_protobuf` is no longer eio specific
Hello, Per your suggestion, I've moved the RPC specification into However, I must admit that exploring a similar typed RPC interface for I'm also considering switching the dependency order between typed and untyped Thank you for your time and consideration. |
Thank you @mbarbin ! This looks very good.
If your PR works well with the latest |
Thank you for sharing the announcement about ocaml-protoc 3.0 and for the In line with your enthusiasm about work being released in this space, I've added While this is a functional proof of concept, the interface isn't as compact as
As demonstrated in the example, the first value is readily available. However, I believe that this can be improved by proposing minor changes to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unrelated diffs you see on this file are due to my editor config which uses format-dune-file on save. After carefully editing the file by other means in the first few commits on the PR, I eventually gave up on trying to keep the file non formatted. Before enabling code review, I think either of the 2 following follow up will be satisfactory:
- I clean up the file and remove formatting changes from the PR
- We add a commit upstream that formats the file, and rebase the PR on top, thus voiding all the formatting changes.
If you have no objections, I favor 2, but I'm open to 1 as well. Thanks!
- Make use of ocaml-protoc's server implementation bundle as intended; - Adapt routeguide example to ocaml-protoc to show the differences. This results in a more complicated [Grpc.Rpc] interface that tries to better capture the common parts between ocaml-protoc and ocaml-protoc-plugin that can be used by ocaml-grpc.
With the help of clarifications from mransan/ocaml-protoc#224 I modified Consequently, I modified the interface in Meanwhile, I duplicated the routeguide example to use ocaml-protoc in order to illustrate the differences in generated interfaces from proto spec, and show how each integrates with ocaml-grpc. |
I've taken some time to reflect on our discussion. There seems to be a tension between crafting a user-friendly API tailored to In my view, the best approach to this tension might be a matter of personal Let's use the routeguide example, built with eio and ocaml-protoc-plugin, as a Consider the following dependency graph 1: This graph shows that the routeguide components depend on grpc-eio and As it stands, the user is the first component where both grpc-eio and This brings me back to my initial message in this conversation. If ocaml-grpc Consider this alternative dependency graph: This modified graph introduces a new component, grpc-protoc-plugin-eio, which Now, grpc-protoc-plugin-eio is the first component where both libraries are in This approach shouldn't lead to code duplication. On the implementation side, An additional benefit of having expanded libraries is that it reduces the I've pushed additional changes to the PRs to add both libraries, grpc-protoc-eio Footnotes |
Thank you @mbarbin for the additional work you put into this PR. I did like your commit supporting both That being said, I'm not convinced that non-parameterized libraries are the way to go. I believe it is best not to introduce a coupling between concurrency/networking (Eio, Lwt, Async) and serialization. I'd also rather not maintain n x m libraries for all possible combinations. I will have some more time next week to look further into this. @tmcgilchrist do you have any opinion on this matter? |
This reverts commit 042efeb.
- This adds type safety to ensure the RPCs are called with the expected protocol (e.g. you cannot call a unary rpc with a server_streaming entry point, etc.). On the ocaml-protoc-plugin side, currently there are no markers for the rpc modes - this interface will permit adding them in the future without user facing changes. On the ocaml-protoc plugin, the value mode flows from the proto file definition and is checked in the user code as expected. Implementation note: There's perhaps a way to shorten the mapping of value-modes but I couldn't find one given that `Grpc` cannot depend on `Ocaml_protoc`, and thus the `Value_mode` types are not equal.
Alright, I've rolled back the previous set of changes for now. We can revisit the topic of non-parametrized libraries when you have the During the now-reverted changes, I had enhanced the type safety between unary
I'm intrigued to understand more about this. Thank you! |
Having played a bit with the latest typed rpc version, I like where it is now with When the design settles down, it would be good to review the generated documentation for the various libraries and provide a clear structure for new users on where to start. Pointing them towards Typed_rpc with a default protobuf serialisation setup. It would be interesting (but not required here) to see if the handler construction can be made to error on duplicate handlers. Right now it matches the first one in the list and ignores any other potential matches. ocaml-grpc/examples/routeguide/src/server.ml Lines 183 to 186 in c0c4df5
Not sure whether the error handling for decode/encode errors lines up with the grpc spec. In general there are some interop issues with go/rust versions of gRPC that I've found, so it's probably no worse than the current released version. Ideally the Finally I wonder what the extra Functor looks like for the generated code and what impact that will have on performance/allocation. I don't have a good benchmarking setup yet to answer this question. |
Thanks @tmcgilchrist for your opinion. I also like where it is now, the balance feels right. Really nice work @mbarbin! |
In the existing examples, the service name is separated from the package name by a dot, which I inadvertently omitted in the previous implementation. Note that as long as the service name used by a client and a server is the same, the right handler is executed, so there's some leeway in the actual choice of the convention to use. The hope is that the dot separated one is standard.
I'm ok to write the Async piece. |
This is extracted from dialohq#48 as a standalone change which should allow staring building the other pieces (eio, lwt, async, protoc & protoc_plugin) independently.
This is extracted from dialohq#48 as a standalone change which should allow staring building the other pieces (eio, lwt, async, protoc & protoc_plugin) independently.
Hello @quernd, I trust you're doing well. I wanted to provide additional context about the
I appreciate your willingness to merge this work. As for the specifics of the My hope is that merging #54 will enable us to open independent PRs for the #50 Add dependencies to fix opam-dune-lint I plan for PRs #48 and #51 to remain in the Draft stage and be closed once #48 Explore Api (draft) The structure I've proposed from #50 to #54 is flexible, so if you have a It's wonderful to see that both you, quernd, and tmcgilchrist have offered to Thank you! |
Thank you @mbarbin for structuring this to be more manageable to review! I am taking a look at the prerequisite PRs now. |
This is extracted from dialohq#48 as a standalone change which should allow starting building the other pieces (eio, lwt, async, protoc & protoc_plugin) independently.
This is extracted from dialohq#48 as a standalone change which should allow starting building the other pieces (eio, lwt, async, protoc & protoc_plugin) independently.
Hello, I wanted to provide an update on my progress and thoughts. Non-parametrized libraryAfter reflecting on our previous discussion, I've come to realize that my goal TestsSerialization (ocaml-protoc)Work is currently underway2 in ocaml-protoc to facilitate automatic roundtrip RPCEio-rpc1 is based on a preview package of Progress and synchronization of workI've noticed a tension between the desire to break down the work into reviewable One potential solution could be to create a long-lived branch (e.g., Footnotes |
Thanks for the writeup. I will be thinking about this now as I'm moving some of our internal endpoints to grpc. I'll be looking at hyper opinionated codegen where you have protoc in -> ready to use RPC methods out, from what I saw your current solution depends on some boilerplate to connect things. I'm also thinking about integrating telemetry in the generated code as well. |
Hi @wokalski, I wasn't working on grpc lately. Great to hear from you again! I tend to view 'opinionated' as 'pragmatic' and 'unopinionated' as 'uninstantiated'. I mention this to help us communicate more effectively. When it comes to boilerplate, I'm open to discussing it further. The perception of what's burdensome can vary, so feel free to get specific. Remember, all my work in the grpc scope has been exploratory and in draft form. I'm keen to continue this exploration and your input helps me do that. Looking forward to our continued discussions. |
Hi @wokalski and team, I hope this message finds you well. I've noticed the recent activity in #56 and the refactor happening in the repository. I'm thrilled to see the project moving forward. I'm looking forward to the new library and I'm interested in contributing to it once it's more stable. In the meantime, given the extent of the refactor, I understand that my open PRs may no longer apply and could potentially cause merge conflicts. With this in mind, I'm proposing to close them (unless you have strong objections ?). This way, you can focus on the refactor without having to worry about potential merge conflicts. Please feel free to use any part of my contributions that you find useful, or disregard anything that doesn't fit into the new refactor. All my contributions are intended to be compatible with the existing license of the repository. Thank you for your hard work on this project and good luck with the refactor. I'm excited to see where the project goes next. Best, |
Thank you for the message and following the project. Yes - I will close the PRs but I won't shy away from stealing some ideas 😄. Also - if you'd like I'd appreciate help with the PR most notably around refactoring Lwt/async implementations to follow eio (I also wrote it all so that there's as much code reuse as possible). A contribution of moving away from the string based APIs for (de)coding would be welcome as well. |
Understood. There's nothing remaining in this draft (#48) that hasn't already been included in #53, #54, #55, so I'll proceed with closing it now. I'll leave the others open for you to close at your convenience. Thank you! Regarding the lwt/async refactoring, I'll defer to @quernd and @tmcgilchrist, who have previously expressed interest in contributing to these parts in the course of this PR conversation. As for the transition away from string-based APIs, I agree that it's a sensible direction for the project but I currently don't have any performance-sensitive use cases, so I may not be the best person to tackle this. I will be awaiting the completion of the refactoring and am optimistic about adapting my usage to align with it. My starting point will likely be eio-rpc. Thanks! |
Happy to implement an lwt and/or async version when the refactoring has settled down, as keeping the three implementations is useful for me. |
Thanks. I will let you know once I'm done. I'm working on it actively shifting between the implementation of the lib and using it in the app to polish the api. |
Hello,
I'm exploring some RPCs libraries in Ocaml that are transitioning to Eio and ocaml-grpc caught my attention. It is nice to see such project under development 😃 Thank you!
I've noticed in the current interface the serialization of messages is left for the user of the library to handle. I wonder why you made that design choice. I was definitely surprised about that when I first looked at the
Grpc_eio
's examples.Is it because you prefer not to depend on a particular protoc plugin in the implementation of
Grpc_eio
, or is there some specific use case where it is necessary to have a fine-grain control over de-serialization error e.g. while iterating through a stream? Do you expect that different users ofGrpc_eio
may be using different OCaml protoc plugins provider (and/or do you want to specifically support this)?If you allow for
Grpc_eio
to depend on a chosen protoc plugin, it is likely some tighter integration becomes possible. In fact, it's perhaps even possible for users not to be exposed to any interface, function or type from the plugin.In this PR I made an exploration along this idea, and drafted an
Grpc_eio
interface that handles the serialization and service names registering with a stronger reliance on the interfaces generated byocaml-protoc-plugin
. I'd be curious to hear your thoughts about this.If you're interested in this sort of direction, I suspect there's more to be done. I'm thinking for example having the plugin generate a marker for the kind of interface each rpc have (server_streaming, client_streaming, unary, bidirectional) - it should be possible to prevent e.g. implementing an interface with the wrong kind (currently the kind annotation from the
*.proto
file doesn't make it to the OCaml generated code, so consistency is to be carefully achieved). There's probably more, I haven't thought much about it for now, I'd rather get some feedback from you first.Thank you!