-
Notifications
You must be signed in to change notification settings - Fork 14
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
api: support for pre-call translation to custom type #11
Comments
I hacked together a quick prototype for this yesterday in branch The primary reason for moving ahead with this pre-call adaptation is as for quorum functions: separation of concerns and encapsulation. We would like to hide technical details related to such adaptation from the implementation of the main protocol flow. I have identified two separate types of adaptation that is relevant. One is actually already implemented in the form of
Both types can be declared in a The per-node version would look like this, where the WriteAdapterAdapter(req *State, node *Node) *MyState (PS: the double The implementation looks just like expected := c.n
replyChan := make(chan internalWriteResponse, expected)
for _, n := range c.nodes {
nodeArg := c.adapt.WriteAdapterAdapter(a, n)
if nodeArg == nil {
expected--
continue
}
go callGRPCWriteAdapter(ctx, n, nodeArg, replyChan)
} The per-call version would look like this, and it would be called only once for each quorum call. WriteAdapterAdapter(req *State) *MyState The implementation would look like: arg := c.adapt.WriteAdapterAdapter(a)
expected := c.n
replyChan := make(chan internalWriteResponse, expected)
for _, n := range c.nodes {
go callGRPCWriteAdapter(ctx, n, arg, replyChan)
} I think both use cases are reasonable and matches the So my question to @s111 and @tormoder is: does it make sense to keep both Any other thoughts on this design? Naming suggestions? PS: The current prototype implementation only implements one of the two adaptation types. |
An alternative to adding two new gorums-level options would be to add var arg *MyState
if c.opts.perCallAdapter != nil {
arg = c.opts.perCallAdapter(a)
} The user would specify these adapters using two functions like so:
The only drawback is that there would be two extra Some issues:
(this was just a quick write up... no prototyping... or careful thought...) |
I've pushed an implementation to the |
I have reread this. Here is a link to the call-adapter branch, for the record. I've come to a few conclusions about this. First, I think there is some merit to providing a feature to separate the logic/concern of pre-call transformations from the logic of the method call, e.g. the signing of individual messages to the group/configuration being called. The However, I've come to dislike the idea of generating code, relying on the options I like better the idea of using However, perhaps a better idea is to design a simple way for users to provide their own interceptors for Gorums, as outlined in #37. Maybe this could even replace the specialized |
Background: We now have support for custom return types that can be returned from the different quorum call variants to encode additional details that does need to be sent on the wire or exposed to the server. We also have support for
perNode
arguments that translate the request parameter to a value to be sent to the different servers. This latter feature is a pre-call translation while the return types are handled by the quorum function and so there is a form of symmetry here.What is missing is a general pre-call translation or adapter that takes one type as input and creates another type that can be sent to the servers. See attached picture.
When is this useful? We can make use of this when we need to create signatures or operate on the input message. We already do something like this for the
byzq
, but without support from Gorums. We implement a method for signing in the quorum spec.How should it be implemented? One obvious solution would be to have the user provide a string option such as
pre_call_adapter
to specify a custom type expected, which would then produce a functionMethodNamePreCallAdapter()
in theQuorumSpec
interface that the user needs to implement.There are some issues regarding the implementation that remains undecided on my end wrt. naming, but I think the principle is very clear to me.
An alternative solution is to define a
per_call_adapter
string in the proto file. Instead of defining thePreCallAdapter
in theQuorumSpec
interface, we can create a separate interface calledMethodNamePreCallAdapter
that Gorums can check for with a type assertion and call it if it exists. That is, if theQuorumSpec
object also implements theMethodNamePreCallAdapter
method, it can invoke this method to do the adaptation. Is this too much magic?Can this somehow be integrated with the
per_node_arg
option, making it so that this named functionMethodNamePrecallAdapter
or something is called, and that can generate either a single message to be sent to all servers or a unique message for each server. This needs some more thinking.The text was updated successfully, but these errors were encountered: