[Golang] Auto-generated workload client
This issue proposes a goworkload
plugin that generates a go module that directly calls services of an application.
Background
Blueprintv1 contains an auto-generated workload client; this is not yet implemented in Blueprintv2. The closest we currently get is in the goproc
plugin, which provides the wiring helper function goproc.CreateClientProcess
; this will package all dependencies and generate a main method that instantiates a client. To get a workload we then need to manually extend this code to invoke methods on the client.
This approach is appropriate for users who want to implement custom workloads, but it is tedious during application and plugin development, when interfaces will be in flux and recompilation commonplace
Proposal
The goworkload
plugin will generate code that is similar to the goproc
plugin. It lets the user specify which service to build a workload client for, but does the following in addition:
1 Has additional command line parameter to choose which function to call. Possibly we could also let the workload contain clients for multiple services, in which case we would have a command line parameter to also choose which service to call 2 Invokes the specified service/function once, printing the output or error. Uses default values for arguments to the service. As a possible extension, we could expose all of the arguments as command line parameters (this might be unnecessarily tedious).
Suggested implementation
There is a neat way of implementing this without duplicating any goproc
code. The plugin can be implemented as a golang node with a run method. The plugin can optionally expose config values (See #3 ) for choosing which function to invoke. The run method makes the calls then exits. The goproc
generated code would execute this completely transparently, and would exit once the run method completes. The generated workload code would simply look something like this:
type NonLeafService_WorkloadGenerator struct {
Service leaf.NonLeafService
}
func New_NonLeafService_WorkloadGenerator(service leaf.NonLeafService) (*NonLeafService_WorkloadGenerator, error) {
workload := &NonLeafService_WorkloadGenerator{}
workload.Service = service
return workload, nil
}
// Blueprint: Run is called automatically in a separate goroutine by runtime/plugins/golang/di.go
func (workload *NonLeafService_WorkloadGenerator) Run(ctx context.Context) error {
fmt.Println("Invoking leaf.NonLeafService.Hello")
ret0, err := workload.Service.Hello(ctx, 55)
if err != nil {
fmt.Printf("Error: %s\n", err.Error())
} else {
fmt.Printf("Received %v\n", ret0)
}
return err
}
Possible complication
For services with complex struct arguments, it's possible that pointers within the struct cause problems by defaulting to nil. The GRPC plugin doesn't yet safely handle pointers in structs.