Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
08 Jul 2025 · 4 mnt baca ·Artikel 30 / 110
Go

30 Studi Kasus: Streaming Progress Update

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Streaming Progress Update Menggunakan Go dan gRPC

Di dunia pengembangan backend modern, pengalaman pengguna yang mulus menjadi perhatian utama. Salah satu tantangan yang sering ditemui adalah bagaimana memberikan update progress secara real-time kepada user, terutama dalam proses backend yang memakan waktu cukup lama seperti parsing, konversi, atau import data besar.

Dalam artikel ini, kita akan membahas studi kasus implementasi Streaming Progress Update menggunakan gRPC Stream di Go (Golang). Kita akan bahas konsep arsitektur, kode implementasi server dan client, dan contoh simulasi dengan tabel serta diagram alur proses.


Permasalahan

Bayangkan sebuah aplikasi desktop atau web yang mengunggah file besar ke backend untuk diproses. Backend memerlukan waktu cukup lama, sementara user tidak diberi tahu progresnya. Hal ini menurunkan UX karena user tidak tahu apakah proses sedang berjalan atau gagal.


Solusi: Streaming Progress via gRPC

gRPC mendukung server-side streaming, memungkinkan server mengirim aliran data berkala ke client dalam satu koneksi gRPC. Ini sangat cocok untuk pengiriman progress update.


Diagram Arsitektur

MERMAID
flowchart LR
    Client -->|StartJob RPC| Server
    Server -->|Stream Progress| Client
    Server -->|Simulasi Proses| Processor


Struktur Proyek

bash
1progress-grpc/
2├── proto/
3│   └── progress.proto
4├── server/
5│   └── main.go
6├── client/
7│   └── main.go

1. Definisi Protobuf

proto/progress.proto

proto
 1syntax = "proto3";
 2
 3package progress;
 4
 5service ProgressService {
 6  rpc StartJob(JobRequest) returns (stream ProgressResponse);
 7}
 8
 9message JobRequest {
10  string job_id = 1;
11}
12
13message ProgressResponse {
14  int32 percent = 1;
15  string message = 2;
16}

Generate dengan:

bash
1protoc --go_out=. --go-grpc_out=. proto/progress.proto

2. Implementasi Server

server/main.go

go
 1package main
 2
 3import (
 4    "context"
 5    "fmt"
 6    "log"
 7    "math/rand"
 8    "net"
 9    "time"
10
11    pb "progress-grpc/proto"
12    "google.golang.org/grpc"
13)
14
15type server struct {
16    pb.UnimplementedProgressServiceServer
17}
18
19func (s *server) StartJob(req *pb.JobRequest, stream pb.ProgressService_StartJobServer) error {
20    progress := 0
21    for progress < 100 {
22        time.Sleep(1 * time.Second)
23        step := rand.Intn(10) + 5
24        progress += step
25        if progress > 100 {
26            progress = 100
27        }
28        msg := fmt.Sprintf("Progress %d%%", progress)
29        stream.Send(&pb.ProgressResponse{
30            Percent: int32(progress),
31            Message: msg,
32        })
33    }
34    return nil
35}
36
37func main() {
38    lis, err := net.Listen("tcp", ":50051")
39    if err != nil {
40        log.Fatalf("failed to listen: %v", err)
41    }
42    s := grpc.NewServer()
43    pb.RegisterProgressServiceServer(s, &server{})
44    log.Println("gRPC server running on :50051")
45    if err := s.Serve(lis); err != nil {
46        log.Fatalf("failed to serve: %v", err)
47    }
48}

3. Implementasi Client

client/main.go

go
 1package main
 2
 3import (
 4    "context"
 5    "log"
 6    "time"
 7
 8    pb "progress-grpc/proto"
 9    "google.golang.org/grpc"
10)
11
12func main() {
13    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
14    if err != nil {
15        log.Fatalf("failed to connect: %v", err)
16    }
17    defer conn.Close()
18
19    client := pb.NewProgressServiceClient(conn)
20    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
21    defer cancel()
22
23    stream, err := client.StartJob(ctx, &pb.JobRequest{JobId: "abc123"})
24    if err != nil {
25        log.Fatalf("error calling StartJob: %v", err)
26    }
27
28    for {
29        msg, err := stream.Recv()
30        if err != nil {
31            log.Printf("stream ended: %v", err)
32            break
33        }
34        log.Printf("[%d%%] %s", msg.Percent, msg.Message)
35    }
36}

Simulasi Output Progress

Berikut simulasi hasil output progress di console client:

text
1[6%] Progress 6%
2[13%] Progress 13%
3[25%] Progress 25%
4[39%] Progress 39%
5[52%] Progress 52%
6[66%] Progress 66%
7[81%] Progress 81%
8[95%] Progress 95%
9[100%] Progress 100%

Tabel Perbandingan Pendekatan

PendekatanKompatibilitasOverheadResponsifCocok untuk
Polling RESTTinggiTinggiLambatTask ringan
WebsocketMenengahSedangCepatInteraktif 2 arah
SSE (EventStream)Tinggi (HTTP)RendahSedangBrowser, 1 arah
gRPC StreamgRPC onlyRendahCepatInternal RPC/Streaming

Kesimpulan

Dengan memanfaatkan server-side streaming gRPC, kita bisa memberikan update progress secara efisien dan real-time. Pendekatan ini ideal untuk aplikasi internal berbasis microservice, CLI, atau desktop client yang terhubung ke backend berbasis Go.

Studi kasus di atas bisa dikembangkan lebih lanjut:

  • Integrasi dengan Redis untuk status job multi-process.
  • Middleware autentikasi gRPC.
  • Penggunaan UUID atau tracing span untuk jobID.

Semoga studi kasus ini membantu kamu memahami cara menerapkan streaming update yang skalabel dan efektif. 🚀

Artikel Terkait

💬 Komentar