Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
09 Sep 2025 · 5 min read ·Article 93 / 110
Go

93. Case Study: Building a Ticket Booking System with gRPC

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

Case Study: Building a Ticket Booking System with gRPC

Welcome to an architectural journey of building a scalable and efficient ticket distribution system. In this article, I’ll break down the design and implementation of a ticket booking microservice using gRPC, from the underlying concepts all the way to ready-to-use code examples.


Background: When HTTP REST Starts to Hit Its Limits

As engineers, we often run into the performance limits of HTTP REST. As an organization grows, API traffic increases, real-time requirements rise, or services become more and more complex, RPC (Remote Procedure Call) solutions like gRPC become very appealing. gRPC, born out of Google, offers efficiency, performance, and service-to-service communication capabilities that are far superior to traditional REST protocols.

Case Study: An Event Ticket Booking System

Imagine you’re building a digital ticket booking system. In a microservice architecture, the key components you’ll need include:

  1. Order Service: Receives order requests and handles temporary payment holds.
  2. Inventory Service: Stores remaining ticket counts and performs atomic stock decrements.
  3. Notification Service: Notifies customers via email/WhatsApp/Push when a booking succeeds.
  4. Auth Service: Manages user authorization.

For this case study, we’ll integrate microservices 1 and 2 using gRPC.


Understanding the System Flow

To keep the booking process efficient and consistent across services, here’s the flowchart:

MERMAID
graph TD
    A[Client] -->|Book Ticket| B(Pemesanan Service)
    B --> |Check & Lock Ticket| C(Inventaris Service)
    C --> |OK| B
    B --> |Confirmed| A
    B --> |Failed| A

The table below details the flow at each step:

StepServiceDescription
Book TicketClient -> OrderTicket purchase request
Check & Lock TicketOrder -> InventoryChecking and locking ticket stock
OK / FailedInventory -> OrderConfirmation of availability or lock failure
Confirmed/FailedOrder -> ClientSuccess/failure notification to the user

Defining the Proto File: gRPC Ticketing

Inter-service communication with gRPC relies on a .proto file to define the contract. It’s simple: just two key methods, Check & Lock the ticket.

protobuf
 1syntax = "proto3";
 2
 3package ticketing;
 4
 5service InventoryService {
 6  rpc CheckAndLock (TicketRequest) returns (TicketResponse) {}
 7}
 8
 9message TicketRequest {
10  string event_id = 1;
11  int32 quantity = 2;
12}
13
14message TicketResponse {
15  bool success = 1;
16  string message = 2;
17}
  • CheckAndLock: Ensures the tickets are available and locks them temporarily.

A Quick Implementation (Golang)

1. Inventory Service

go
 1// inventory_service.go
 2type InventoryServiceServer struct {
 3    mu sync.Mutex
 4    tickets map[string]int // eventID -> remaining tickets
 5}
 6
 7func (s *InventoryServiceServer) CheckAndLock(ctx context.Context, req *pb.TicketRequest) (*pb.TicketResponse, error) {
 8    s.mu.Lock()
 9    defer s.mu.Unlock()
10
11    stock := s.tickets[req.EventId]
12    if stock < int(req.Quantity) {
13        return &pb.TicketResponse{Success: false, Message: "Not enough tickets"}, nil
14    }
15    s.tickets[req.EventId] -= int(req.Quantity)
16    return &pb.TicketResponse{Success: true, Message: "Locked"}, nil
17}

2. Order Service (gRPC Client)

go
 1// order_service.go
 2conn, _ := grpc.Dial("inventaris:50051", grpc.WithInsecure())
 3client := pb.NewInventoryServiceClient(conn)
 4
 5resp, err := client.CheckAndLock(ctx, &pb.TicketRequest{
 6    EventId: "EVT123",
 7    Quantity: 2,
 8})
 9
10if err != nil || !resp.Success {
11    // handle booking failure
12}

Multi-Client Simulation: The Race Condition Problem

The biggest challenge in a ticketing application is the race condition (two people checking out the same ticket almost simultaneously). Here’s a simple simulation (pseudocode):

go
1go func() {
2    // Client A
3    client.CheckAndLock(ctx, TicketRequest{EventId: "EVT123", Quantity: 2})
4}()
5go func() {
6    // Client B
7    client.CheckAndLock(ctx, TicketRequest{EventId: "EVT123", Quantity: 2})
8}()

In the InventoryService, locking the stock with a mutex (mu.Lock()) keeps the process atomic and prevents overselling.


Advantages of gRPC in a Ticketing System

  1. Performance: gRPC uses Protobuf, which is faster and more bandwidth-efficient.
  2. Bidirectional Streaming: Supports two-way streaming, useful for real-time notifications to the client.
  3. Contract First API: Validation via the proto makes integration more disciplined and drastically reduces inter-service errors.
  4. Polyglot Friendly: Orders from a Go backend, inventory from Java, notifications from Python? It all works because gRPC has bindings for many languages.

Comparing Performance: REST vs gRPC

AspectREST (JSON/HTTP)gRPC (Protobuf/HTTP2)
SerializationSlow, bulky JSONBlazing fast, compact
Latency3–6x higherVery low
MultilingualManual client neededAutomatic via codegen
StreamingHard/limitedBuilt-in, native
ConcurrencyManual locking, slow HTTPHTTP/2 native multithreaded

Reality on the Ground: Partial Failure & Retry Scenarios

gRPC offers deadline and retry features to automatically handle failed requests—features that are highly relevant in a ticket booking system that demands a high SLA.

go
1ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
2defer cancel()
3
4_, err := client.CheckAndLock(ctx, &pb.TicketRequest{...})
5if grpc.Code(err) == codes.DeadlineExceeded {
6    // retry logic
7}

Engineering Tips for a gRPC Ticket System

  1. Timeout & Retry: Always set a retry strategy. Don’t let the client wait indefinitely.
  2. Distributed Lock: At large scale, use a distributed lock (for example, Redis redlock) so that stock stays consistent across many replicas.
  3. Observability: Take advantage of gRPC interceptors for tracing and logging.
  4. Interface Backward Compatibility: Don’t remove proto fields without a fallback/versioning strategy.

Conclusion

Applying gRPC in a ticket booking system delivers a boost in performance, data consistency, and scalability. It’s a great fit for polyglot microservices ecosystems that demand low latency and handle high traffic.

Where should you start? Try replicating the scenario above, run a benchmark against REST/HTTP, and enjoy a more reliable architecture for nationwide-scale ticket distribution systems.

Danger
Are you already using gRPC for critical services at your company? Share your experience in the comments!

References:


See you in the next post. Don’t forget to give it a 👏 and share if you found it helpful!

Related Articles

💬 Comments