Spring Boot + gRPC Deadline Example
According to the gRPC documentation the gRPC client has no default timeout. So the gRPC client will keep on waiting indefinitely. This is not the behaviour that we want. We want our solutions to be fail fast.

In this tutorial we will be implementing gRPC deadline for the gRPC client using which we specify that the gRPC client should only wait for a limited amount of time else it should throw an exception. This helps prevent the client from waiting forever if the server is taking too long to respond.
Using a gRPC deadline can be useful in scenarios where timely responses are critical. For example, in a real-time messaging application, setting a deadline ensures that users receive responses quickly without experiencing delays. It also helps manage network resources efficiently by preventing connections from being tied up indefinitely waiting for a response. Ultimately, gRPC deadlines help improve the overall performance and responsiveness of client-server communication.

Video
This tutorial is explained in the below Youtube Video.gRPC - Table of Contents
Spring Boot+ gRPC Hello World Example Spring Boot gRPC Server + C# gRPC Client Example Spring Boot 3 + gRPC - Types of gRPC Spring Boot 3 + gRPC Unary Example Spring Boot 3 + gRPC Server Streaming Example Spring Boot 3 + gRPC Client Streaming Example Spring Boot 3 + gRPC Bidirectional Streaming Example Spring Boot + gRPC Deadline Example Spring Boot + gRPC Error Handling Example Spring Boot + gRPC Error Handling - Using Metadata Trailer Spring Boot + gRPC Error Handling - Global Exception Handler Using GrpcAdvice
Implementation
We will be modifying the code we had implemented for Spring Boot gRPC + Server Streaming Example.For Server Streaming we had implemented the following code where there is a delay of 5 secs before sending the streaming data.
package com.javainuse.bank.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import com.javainuse.bank.model.Transaction;
import com.javainuse.banking.AccountRequest;
import com.javainuse.banking.TransactionDetail;
import com.javainuse.banking.TransactionDetailList;
import com.javainuse.banking.TransactionServiceGrpc;
import io.grpc.Metadata;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class TransactionHistoryService extends TransactionServiceGrpc.TransactionServiceImplBase {
@Override
public void streamTransactions(AccountRequest request, StreamObserver<TransactionDetailList> responseObserver) {
// Assuming you have a method to fetch transaction details based on the duration
// in days
List<Transaction> transactions = fetchTransactions(request.getDurationInDays());
int batchSize = 3; // How many transactions to send at once
for (int i = 0; i < transactions.size(); i += batchSize) {
int endIndex = Math.min(i + batchSize, transactions.size());
List<Transaction> batchTransactions = transactions.subList(i, endIndex);
TransactionDetailList.Builder transactionDetailListBuilder = TransactionDetailList.newBuilder();
for (Transaction transaction : batchTransactions) {
TransactionDetail transactionDetail = createTransactionDetailFromTransaction(transaction);
transactionDetailListBuilder.addTransactionDetails(transactionDetail);
}
TransactionDetailList transactionDetailList = transactionDetailListBuilder.build();
responseObserver.onNext(transactionDetailList);
// Delay between sending batches (if necessary)
// You can adjust this based on your requirements
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
responseObserver.onError(e);
return;
}
}
// Send completion of response with final metadata
responseObserver.onCompleted();
}
private TransactionDetail createTransactionDetailFromTransaction(Transaction transaction) {
return TransactionDetail.newBuilder().setTransactionId(transaction.getId())
.setTransactionType(transaction.getType()).setTransactionAmount(transaction.getAmount()).build();
}
private List<Transaction> fetchTransactions(int durationInDays) {
List<Transaction> transactions = new ArrayList<>();
// Mock data for transaction details
Transaction transaction1 = new Transaction("1", "Deposit", 100.0f);
Transaction transaction2 = new Transaction("2", "Withdrawal", 50.0f);
Transaction transaction3 = new Transaction("3", "Transfer", 75.0f);
Transaction transaction4 = new Transaction("4", "Deposit", 200.0f);
Transaction transaction5 = new Transaction("5", "Withdrawal", 30.0f);
transactions.addAll(Arrays.asList(transaction1, transaction2, transaction3, transaction4, transaction5));
return transactions;
}
}
The client code makes use of the async stub to call the server stream gRPC server.
When we run the client code we get the following output after 5 seconds.

Let us now implement the gRPC client deadline which sepcifies a timeout value of 2 seconds. So if the client does not get a response till 2 seconds it will throw a DEADLINE_EXCEEDED exception.
package com.javainuse.bank.service;
import java.util.concurrent.TimeUnit;
import com.javainuse.banking.AccountRequest;
import com.javainuse.banking.TransactionDetailList;
import com.javainuse.banking.TransactionServiceGrpc;
import io.grpc.Deadline;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;
public class TransactionServiceClient {
private final ManagedChannel channel;
private final TransactionServiceGrpc.TransactionServiceStub asyncStub;
public TransactionServiceClient(String host, int port) {
this(ManagedChannelBuilder.forAddress(host, port).usePlaintext().build());
}
public TransactionServiceClient(ManagedChannel channel) {
this.channel = channel;
asyncStub = TransactionServiceGrpc.newStub(channel);
}
public void streamTransactions(String accountNumber, int durationInDays) {
AccountRequest request = AccountRequest.newBuilder().setAccountNumber(accountNumber)
.setDurationInDays(durationInDays).build();
asyncStub.withDeadline(Deadline.after(2, TimeUnit.SECONDS)).streamTransactions(request,
new StreamObserver<TransactionDetailList>() {
@Override
public void onNext(TransactionDetailList transactionDetail) {
// Handle each incoming TransactionDetail here
System.out.println("Received transaction detail: " + transactionDetail);
}
@Override
public void onError(Throwable throwable) {
System.err.println("Error occurred during transaction streaming: " + throwable);
}
@Override
public void onCompleted() {
System.out.println("Transaction streaming completed");
}
});
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(3, TimeUnit.SECONDS);
}
}
If we run the client we now get the io.grpc.StatusRuntimeException: DEADLINE_EXCEEDED exception.

Download Source Code
Download it - Spring Boot + gRPC Deadline Client ExampleDownload it - Spring Boot + gRPC Deadline Server Example
Popular Posts
1Z0-830 Java SE 21 Developer Certification
1Z0-819 Java SE 11 Developer Certification
1Z0-829 Java SE 17 Developer Certification
AWS AI Practitioner Certification
AZ-204 Azure Developer Associate Certification
AZ-305 Azure Solutions Architect Expert Certification
AZ-400 Azure DevOps Engineer Expert Certification
DP-100 Azure Data Scientist Associate Certification
AZ-900 Azure Fundamentals Certification
PL-300 Power BI Data Analyst Certification
Spring Professional Certification
Azure AI Foundry Hello World
Azure AI Agent Hello World
Foundry vs Hub Projects
Build Agents with SDK
Bing Web Search Agent
Function Calling Agent
Spring Boot + Azure Key Vault Hello World Example
Spring Boot + Elasticsearch + Azure Key Vault Example
Spring Boot Azure AD (Entra ID) OAuth 2.0 Authentication
Deploy Spring Boot App to Azure App Service
Secure Azure App Service using Azure API Management
Deploy Spring Boot JAR to Azure App Service
Deploy Spring Boot + MySQL to Azure App Service
Spring Boot + Azure Managed Identity Example
Secure Spring Boot Azure Web App with Managed Identity + App Registration
Elasticsearch 8 Security - Integrate Azure AD OIDC