Backend Development 13 min read

Tars Tutorial for Go Developers – Communication Modes, Server and Client Implementation

This tutorial explains how Go developers can generate Tars RPC code from IDL, implement server and client logic, configure server and client settings, use various call patterns such as context, one‑way, mod‑hash and consistent‑hash, and quickly scaffold projects with the tarsgo tool.

TAL Education Technology
TAL Education Technology
TAL Education Technology
Tars Tutorial for Go Developers – Communication Modes, Server and Client Implementation

This article is the second part of the "Tars tutorial for Go developers" series, focusing on communication modes and the implementation of both server and client components.

Example IDL

module order {
    struct Order {
        1 require string id;
        2 optional vector
items;
        3 optional string description;
        4 require float price;
        5 optional string destination;
    };

    interface OrderManagement {
        Order getOrder(string orderId);
    };
};

Generating Go protocol code

tars2go -outdir=. \
  -module=github.com/lbbniu/TarsGo-tutorial \
  proto/order.tars

The generated files are placed under order and proto directories.

Server Implementation

Service definition

interface OrderManagement {
    Order getOrder(string orderId);
};
type OrderManagementServant interface {
    GetOrder(orderId string) (ret Order, err error)
}

type OrderManagementServantWithContext interface {
    GetOrder(tarsCtx context.Context, orderId string) (ret Order, err error)
}

The business logic implements the above interface:

package servant

import (
    "context"
    "net/http"
    "github.com/TarsCloud/TarsGo/tars"
    "github.com/lbbniu/TarsGo-tutorial/order"
)

var orders = make(map[string]order.Order)

type OrderCtx struct{}

var _ order.OrderManagementServantWithContext = (*OrderCtx)(nil)

func NewOrderCtx() *OrderCtx {
    o := &OrderCtx{}
    o.init()
    return o
}

func (o *OrderCtx) init() {
    orders["1"] = order.Order{Id: "1", Price: 100, Items: []string{"iPhone 11", "MacBook Pro"}, Description: "MacBook Pro", Destination: "Beijing"}
}

func (o *OrderCtx) GetOrder(tarsCtx context.Context, orderId string) (ret order.Order, err error) {
    ord, exists := orders[orderId]
    if exists {
        return ord, nil
    }
    return ord, tars.Errorf(http.StatusNotFound, "Order does not exist. : ", orderId)
}

Starting the server:

package main

import (
    "github.com/TarsCloud/TarsGo/tars"
    "github.com/lbbniu/TarsGo-tutorial/internal/servant"
    "github.com/lbbniu/TarsGo-tutorial/order"
)

func main() {
    cfg := tars.GetServerConfig()
    imp := new(servant.Order)
    app := new(order.OrderManagement)
    app.AddServantWithContext(imp, cfg.App+"."+cfg.Server+".orderObj")
    tars.Run()
}

Server configuration details

The tars.GetServerConfig() function returns a struct containing fields such as Node , App , Server , LogPath , Adapters , timeout settings, TLS options, and more. The article lists the most important fields and their meanings.

Configuration file

<tars>
  <application>
    <server>
        app=Test
        server=OrderServer
        local=tcp -h 127.0.0.1 -p 10027 -t 30000
        logpath=/tmp
        <Test.OrderServer.OrderObjAdapter>
            allow
            endpoint=tcp -h 127.0.0.1 -p 8080 -t 60000
            handlegroup=Test.OrderServer.OrderObjAdapter
            maxconns=200000
            protocol=tars
            queuecap=10000
            queuetimeout=60000
            servant=Test.OrderServer.OrderObj
            threads=1
        </Test.OrderServer.OrderObjAdapter>
    </server>
  </application>
</tars>

Client Implementation

The client can call the service without writing any protocol‑specific code.

Simple call (no context)

package main

import (
    "fmt"
    "github.com/TarsCloud/TarsGo/tars"
    "github.com/lbbniu/TarsGo-tutorial/order"
)

func main() {
    comm := tars.GetCommunicator()
    client := new(order.OrderManagement)
    obj := "Test.OrderServer.OrderObj@tcp -h 127.0.0.1 -p 8080 -t 60000"
    comm.StringToProxy(obj, client)
    noCtxCall(client)
}

func noCtxCall(client *order.OrderManagement) {
    order, err := client.GetOrder("1")
    if err != nil {
        panic(err)
    }
    fmt.Printf("noctx: %+v\n", order)
}

Call with context

func ctxCall(client *order.OrderManagement) {
    order, err := client.GetOrderWithContext(context.Background(), "1")
    if err != nil {
        panic(err)
    }
    fmt.Printf("ctx: %+v\n", order)
}

One‑way call

// One‑way call, no return value
func oneWayCall(client *order.OrderManagement) {
    _, err := client.GetOrderOneWayWithContext(context.Background(), "1")
    if err != nil {
        panic(err)
    }
    fmt.Println("oneway")
}

Mod‑hash and consistent‑hash calls

func modHashCall(client *order.OrderManagement) {
    ctx := current.ContextWithClientCurrent(context.Background())
    var hashCode uint32 = 1
    current.SetClientHash(ctx, int(tars.ModHash), hashCode)
    order, err := client.GetOrderWithContext(context.Background(), "1")
    if err != nil {
        panic(err)
    }
    fmt.Printf("ModHash: %+v\n", order)
}

func consistentHashCall(client *order.OrderManagement) {
    ctx := current.ContextWithClientCurrent(context.Background())
    var hashCode uint32 = 1
    current.SetClientHash(ctx, int(tars.ConsistentHash), hashCode)
    order, err := client.GetOrderWithContext(context.Background(), "1")
    if err != nil {
        panic(err)
    }
    fmt.Printf("ConsistentHash: %+v\n", order)
}

Client configuration

type clientConfig struct {
    Locator                     string
    Stat                        string
    Property                    string
    ModuleName                  string
    RefreshEndpointInterval     int
    ReportInterval              int
    CheckStatusInterval         int
    KeepAliveInterval           int
    AsyncInvokeTimeout          int
    SyncInvokeTimeout           int
    ClientQueueLen              int
    ClientIdleTimeout          time.Duration
    ClientReadTimeout           time.Duration
    ClientWriteTimeout          time.Duration
    ClientDialTimeout           time.Duration
    ReqDefaultTimeout          int32
    ObjQueueMax                 int32
}

The article also shows how to write a tarsgo scaffold command to generate a new project, the command used, and the resulting file tree.

Conclusion

After following the steps, developers can quickly build a complete TarsGo service, from IDL definition to server and client code, configuration, and project scaffolding.

BackendmicroservicesRPCGoTutorialTARS
TAL Education Technology
Written by

TAL Education Technology

TAL Education is a technology-driven education company committed to the mission of 'making education better through love and technology'. The TAL technology team has always been dedicated to educational technology research and innovation. This is the external platform of the TAL technology team, sharing weekly curated technical articles and recruitment information.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.