ข้ามไปยังเนื้อหา

Writing a Client

gRPC client สร้างจาก object 2 ตัว:

  • channel — connection ที่อายุยาวไปยัง address ของ server (host:port) channel จัดการ HTTP/2 connection ข้างใต้, การ reconnect และ load balancing
  • stub — wrapper บาง ๆ ที่มี type สร้าง จาก channel เปิด method หนึ่งตัวต่อ rpc การเรียก stub.GetUser(req) จะส่ง request ผ่าน channel แล้วคืน response
flowchart LR
  stub["stub.GetUser(req)"] --> channel["channel
(host:port, HTTP/2)"]
  stub2["stub.GetUser(req2)"] --> channel
  channel -->|multiplexed| server["server :50051"]
channel รับทุก call; stub คือหน้าตาที่มี type

stub ทั้งสองตัวใช้ channel เดียวกัน — นั่นแหละคือประเด็น channel สร้างแพงแต่แชร์ถูก; ส่วน stub เป็นแค่ typed handle ที่วางทับอยู่ข้างบน

นี่คือ client ครบชุดที่สร้าง channel, สร้าง stub, เรียก GetUser แล้วจัดการทั้ง response และ error ที่อาจเกิด:

conn, err := grpc.NewClient("localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
defer conn.Close() // close the channel when the program ends, not per call
client := userv1.NewUserServiceClient(conn) // stub
user, err := client.GetUser(ctx, &userv1.GetUserRequest{Id: 42})
if err != nil {
st, _ := status.FromError(err) // inspect the gRPC status
log.Fatalf("call failed: %s%s", st.Code(), st.Message())
}
fmt.Println(user.Name)

สังเกตว่า error ไม่ใช่ exception เรื่อง network — แต่เป็น status ที่มี code (NOT_FOUND, DEADLINE_EXCEEDED, UNAVAILABLE) และ message client จะ branch ตาม code นั้น

ความผิดพลาดของ client ที่พบบ่อยที่สุดคือสร้าง channel ใหม่ทุก request channel ต้องตั้ง HTTP/2 connection, name resolution และ state ของ load balancing — ทำแบบนั้นต่อ call คือทิ้งประสิทธิภาพที่ดีที่สุดของ gRPC และอาจทำให้ socket หมดตอน load สูง

สร้าง channel เดียวต่อ target ตอน startup แล้วแชร์ ให้ทุก call และทุก stub ปิด channel แค่ตอนโปรแกรม shutdown เท่านั้น

stub ที่ generate มามักให้ทั้งสองแบบ: call แบบ blocking/synchronous ที่คืน response (ง่ายสุดสำหรับ script และ request handler) และแบบ async/future ที่คืนทันทีแล้วเสร็จทีหลัง (มีประโยชน์สำหรับ fan-out หรือ server แบบ non-blocking) เลือกตามจุดเรียกใช้ ทั้งคู่วิ่งผ่าน channel เดียวกัน

gRPC client สร้างจาก object 2 ตัวอะไร?
ความผิดพลาดของ client ที่พบบ่อยที่สุดคืออะไร?
เมื่อ call ล้มเหลว client ได้รับอะไรจริง ๆ?
ควรปิด channel เมื่อไร?