Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC.
Thrift.jl is an implementation of Thrift for Julia, including a plugin for the Thrift IDL compiler.
Setting up Thrift for Julia
Install the Julia Thrift package:
Generating "Hello Julia"
A sample Hello Julia IDL and implementation is bundled along with the Thrift.jl package. It can be found under
test/hello folder of the package.
It contains a Thrift IDL named
hello.thrift, which contains a service
SayHello with a
hello method that returns a hello message for the supplied name in a randomly chosen language.
Generate Julia sources from the IDL.
Thrift.generate("hello.thrift")in the Julia REPL. This should result in a
gen-jlfolder with sources generated from the IDL placed in a folder
hello(named after the IDL file name).
Examine the generated files. Below is a brief explanation of the contents of the generated files.
hello_types.jl: contains Julia types for Thrift structs, exceptions and enums declared explicitly in the IDL along with other implicit types generated by the code generator.
hello_constants.jl: contains any constants declared in the IDL
SayHello.jl: code generated for the
hello.jl: contains a module named
hello(named after the IDL file name), that includes the above mentioned generated files. It also includes a file named
hello_impl.jlthat is not generated, but must be created by the user.
Implementing "Hello Julia"
An implementation of the service methods are already provided as
hello_impl.jl in the
test/hello folder. It has an implementation of
hello service method, that appends a randomly chosen greeting from the constant array
GREETINGS to the supplied name.
- Place the
hello_impl.jlfile in the
- The client and server implementations for this are already provided as
srvr.jl. Start the server with
julia srvr.jl. Run the client with the command
Setting and Getting Fields
Types used as Thrift structures are regular Julia types and the Julia syntax to set and get struct properties can be used on them.
With fields that are set as optional, it is possible that some of them may not have been present in the instance that was read. The
hasproperty method can be used to check before accessing such fields, otherwise an exception may be thrown on accessing a non-existent property.
getproperty(obj, prop::Symbol): Same as
obj.prop. Gets the value if it has been set. Throws an error otherwise.
setproperty!(obj, prop::Symbol, val): Same as
obj.prop = val. The value would be written on the wire when
hasproperty(obj, prop::Symbol): Checks whether property
prophas been set in
clear(obj): Marks all fields of
The default constructor of Thrift structures make it easy to set large types with many properties during construction:
T(; nvpairs...). For example:
julia> obj = MyThriftType(; prop1=1, prop2="hello");
copy!(to, from): shallow copy of objects
isfilled(obj): whether all mandatory fields are set
enumstr(enumname, enumvalue::Int32): returns a string with the enum field name matching the value
generate(specfile): generate Julia code for given Thrift IDL specification
On the Generated Code Structure
The generated code largely follows the scheme used in other languages, e.g. Python and C++. Each Thrift program (IDL file) is placed into a separate folder. The program (IDL file) name must be different from any of the service names defined in the program. Generated files may get clobbered if that is violated, because of filename clashes.
A Julia module is also generated bundle all sources together. Using the module is optional, though convenient in most cases. The example in
test/calculator illustrates how to include multiple thrift generated services in a single Julia module, without using the autogenerated modules.
The generated service
Processor now assumes that the implemented methods are present in the current module. Thus the generated code is not a complete module and requires the user to supply a service implementation to be complete. An alternative would be to make the generated code a complete module, and have the user supply an implementation module.
Service extensions are supported. The thrift processor on the server side passes on any methods it can not handle to the processor it extends from. Extensions of service clients are supported through Julia type extension.
The code generator can be tweaked in the future towards any preferred way of usage that may appear with further usage.
Following is the status of protocols, transports and servers supported in the current implementation:
|Socket||TSocket and TServerSocket|
|SASL||TSASLClientTransport||Only client side implementation as of now|
|Memory||TMemoryTransport||Can't be used with servers as of now|
|File||TFileTransport||Can't be used with servers as of now|
|Blocking. Single Task.||TSimpleServer||Single process, blocking|
|Non Blocking Tasks.||TTaskServer||Single process. Asynchronous task spawned for each connection.|
|Non Blocking Multi Process.||TProcessPoolServer||Multi process, non blocking.|