quartz
Quartz enables you to call Go code from within your Ruby code. This is accomplished by running a Go program as a child process of your Ruby application and using UNIX domain sockets for communication.
With this gem, you can now write performance critical code in Go, and that code can be called from anywhere in a Ruby project.
To see some real world examples where Go can aid a Ruby project, please see
the examples/
directory.
Defining exportable structs
Quartz shares Go code by exporting methods on a struct to Ruby.
Quartz requires that all arguments to exported struct methods be JSON serializable
types. Additionally, the arguments to an exported method should be of the form
(A, *B)
, where A
and B
are JSON serializable types. The method should also
return an error. Here's an example of an exportable struct and method:
type Adder struct{}
type Args struct {
A int
B int
}
type Response struct {
Sum int
}
func (t *Adder) Add(args Args, response *Response) error {
*response = Response{args.A + args.B}
return nil
}
For more information regarding Go's RPC rules, which must still be followed
when using quartz, please examine the official documentation for
the net/rpc
package here.
Preparing a Quartz RPC server in Go
Instead of integrating Quartz into an existing Go application, it is recommended to create a new program that explicitly defines the structs that should be available to Ruby.
First, import the Go package:
import (
"github.com/DavidHuie/quartz/go/quartz"
)
Quartz maintains most of Go's native RPC interface. Thus, export a struct
by calling this in your main
function:
myAdder := &Adder{}
quartz.RegisterName("my_adder", myAdder)
Once all structs have been declared, start the RPC server (this is a blocking call):
quartz.Start()
In Ruby
Naturally:
$ gem install quartz
If you have a go run
-able file, you can create a Go client that
points to that file:
client = Quartz::Client.new(file_path: 'my_adder.go')
If you compiled the Go program yourself, you can create a client that points to the binary like this:
client = Quartz::Client.new(bin_path: 'my_adder_binary')
To list exported structs:
client.structs
=> [:my_adder]
To list a struct's exported methods:
client[:my_adder].struct_methods
=> ["Add"]
To call a method on a struct:
client[:my_adder].call('Add', 'A' => 2, 'B' => 5)
=> { 'Sum' => 7 }
By default the unix socket is created under /tmp
. If you want to change that
you can pass the socket_dir
option.
client = Quartz::Client.new(bin_path: 'my_adder_binary', socket_dir: '/apps/my_app/tmp')
If you want to manage the Go process manually, you can use the following system to set the socket path manually. Now, you can use Systemd/Kubernetes/etc. to manage the Go process.
$ QUARTZ_SOCKET=/tmp/custom.sock ./go_process
client = Quartz::Client.new(socket_path: '/tmp/custom.sock')
Copyright
Copyright (c) 2018 David Huie. See LICENSE.txt for further details.