CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-grpc--grpc-services

gRPC service utilities providing health checking, server reflection, channelz observability, and binary logging capabilities

Pending
Overview
Eval results
Files

admin-services.mddocs/

Admin Services

Collection of standard administrative services for gRPC servers including all built-in observability and management services. Provides a convenient way to add multiple admin services to your gRPC server.

Capabilities

AdminInterface

Utility class that provides a collection of standard gRPC administrative services, including channelz, health checking, and server reflection.

/**
 * Provides a class of services for exposing the overall state of gRPC activity.
 * Offers standard administrative services in a single collection.
 */
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/7929")
@ThreadSafe
public final class AdminInterface {
  
  /**
   * Returns a list of gRPC's built-in admin services
   * @return List of ServerServiceDefinition containing standard admin services
   */
  public static List<ServerServiceDefinition> getStandardServices();
}

Usage Examples:

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.services.AdminInterface;

// Add all standard admin services to your server
public class AdminEnabledServer {
    
    public static void main(String[] args) throws Exception {
        Server server = ServerBuilder.forPort(8080)
            // Add all standard admin services at once
            .addServices(AdminInterface.getStandardServices())
            
            // Add your business services
            .addService(new UserService())
            .addService(new OrderService())
            .build();
        
        server.start();
        System.out.println("Server started with admin services on port 8080");
        
        // Print available admin services
        System.out.println("Available admin services:");
        AdminInterface.getStandardServices().forEach(service -> 
            System.out.println("  - " + service.getServiceDescriptor().getName())
        );
        
        server.awaitTermination();
    }
}

Standard Services Included

The AdminInterface provides the following standard services:

Channelz Service

  • Service Name: grpc.channelz.v1.Channelz
  • Purpose: Runtime introspection and debugging
  • Endpoints: Channel, server, and socket information

Health Service

  • Service Name: grpc.health.v1.Health
  • Purpose: Health checking for load balancers
  • Endpoints: Health status reporting

Server Reflection Service

  • Service Name: grpc.reflection.v1.ServerReflection
  • Purpose: Service discovery and debugging tools
  • Endpoints: Protocol buffer reflection

Production Server Example

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.services.AdminInterface;
import io.grpc.protobuf.services.HealthStatusManager;

public class ProductionServer {
    private final Server server;
    private final HealthStatusManager healthManager;
    
    public ProductionServer(int port) {
        // Create health manager for additional control
        this.healthManager = new HealthStatusManager();
        
        this.server = ServerBuilder.forPort(port)
            // Add standard admin services
            .addServices(AdminInterface.getStandardServices())
            
            // Override health service with our managed instance
            .addService(healthManager.getHealthService())
            
            // Add business services
            .addService(new UserService())
            .addService(new OrderService())
            .addService(new PaymentService())
            .build();
    }
    
    public void start() throws IOException {
        server.start();
        
        // Set initial health status
        healthManager.setStatus("", ServingStatus.SERVING);
        healthManager.setStatus("com.example.UserService", ServingStatus.SERVING);
        healthManager.setStatus("com.example.OrderService", ServingStatus.SERVING);
        healthManager.setStatus("com.example.PaymentService", ServingStatus.SERVING);
        
        System.out.println("Production server started on port " + server.getPort());
        System.out.println("Admin services available for monitoring and debugging");
        
        // Add shutdown hook
        Runtime.getRuntime().addShutdownHook(new Thread(this::gracefulShutdown));
    }
    
    private void gracefulShutdown() {
        System.out.println("Initiating graceful shutdown...");
        
        // Mark services as not serving
        healthManager.setStatus("", ServingStatus.NOT_SERVING);
        
        // Wait for load balancers to drain traffic
        try {
            Thread.sleep(10000); // 10 second drain period
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // Enter terminal state and shutdown
        healthManager.enterTerminalState();
        server.shutdown();
        
        try {
            if (!server.awaitTermination(30, TimeUnit.SECONDS)) {
                server.shutdownNow();
            }
        } catch (InterruptedException e) {
            server.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
    
    public void awaitTermination() throws InterruptedException {
        server.awaitTermination();
    }
}

Development Server with Enhanced Admin Services

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.services.AdminInterface;
import io.grpc.protobuf.services.ProtoReflectionServiceV1;
import io.grpc.protobuf.services.BinaryLogs;

public class DevelopmentServer {
    
    public static void main(String[] args) throws Exception {
        // Enhanced development server with additional debugging capabilities
        BinaryLog binaryLog = BinaryLogs.createBinaryLog(); // Debug logging
        
        Server server = ServerBuilder.forPort(8080)
            // Add standard admin services
            .addServices(AdminInterface.getStandardServices())
            
            // Add enhanced reflection service (latest version)
            .addService(ProtoReflectionServiceV1.newInstance())
            
            // Enable binary logging for debugging
            .setBinaryLog(binaryLog)
            
            // Add business services
            .addService(new UserService())
            .addService(new OrderService())
            .build();
        
        server.start();
        
        System.out.println("Development server started on port 8080");
        System.out.println("\nAvailable debugging tools:");
        System.out.println("  grpcurl -plaintext localhost:8080 list");
        System.out.println("  grpcurl -plaintext localhost:8080 grpc.health.v1.Health/Check");
        System.out.println("  grpcurl -plaintext localhost:8080 grpc.channelz.v1.Channelz/GetTopChannels");
        
        server.awaitTermination();
    }
}

Microservices Architecture Integration

public class MicroserviceWithAdminServices {
    private final Server server;
    private final HealthStatusManager healthManager;
    private final MetricRecorder metricRecorder;
    
    public MicroserviceWithAdminServices(String serviceName, int port) {
        this.healthManager = new HealthStatusManager();
        this.metricRecorder = MetricRecorder.newInstance();
        
        this.server = ServerBuilder.forPort(port)
            // Standard admin services for observability
            .addServices(AdminInterface.getStandardServices())
            
            // Override with managed health service
            .addService(healthManager.getHealthService())
            
            // Add service-specific business logic
            .addService(createBusinessService(serviceName))
            
            // Add interceptors for metrics
            .intercept(new MetricsInterceptor(metricRecorder))
            .build();
    }
    
    private BindableService createBusinessService(String serviceName) {
        switch (serviceName) {
            case "user-service":
                return new UserService();
            case "order-service":
                return new OrderService();
            case "payment-service":
                return new PaymentService();
            default:
                throw new IllegalArgumentException("Unknown service: " + serviceName);
        }
    }
    
    public void start() throws IOException {
        server.start();
        
        // Set healthy status
        healthManager.setStatus("", ServingStatus.SERVING);
        
        // Start metrics reporting
        startMetricsReporting();
        
        System.out.println("Microservice started on port " + server.getPort());
        System.out.println("Admin services enabled for service mesh integration");
    }
    
    private void startMetricsReporting() {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        
        scheduler.scheduleAtFixedRate(() -> {
            metricRecorder.setCpuUtilizationMetric(getCurrentCpuUsage());
            metricRecorder.setMemoryUtilizationMetric(getCurrentMemoryUsage());
            metricRecorder.setQpsMetric(getCurrentQps());
        }, 0, 30, TimeUnit.SECONDS);
    }
    
    private double getCurrentCpuUsage() {
        // Implementation to get CPU usage
        return Math.random() * 0.8; // Example
    }
    
    private double getCurrentMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        return (double) (runtime.totalMemory() - runtime.freeMemory()) / runtime.maxMemory();
    }
    
    private double getCurrentQps() {
        // Implementation to calculate QPS
        return Math.random() * 1000; // Example
    }
}

Monitoring and Observability Integration

public class ObservableServer {
    
    public static void main(String[] args) throws Exception {
        // Server with comprehensive observability
        Server server = ServerBuilder.forPort(8080)
            // Standard admin services
            .addServices(AdminInterface.getStandardServices())
            
            // Business services
            .addService(new UserService())
            
            // Add interceptors for detailed observability
            .intercept(new LoggingInterceptor())
            .intercept(new TracingInterceptor())
            .intercept(new MetricsInterceptor())
            .build();
        
        server.start();
        
        // Start admin service monitoring
        startAdminServiceMonitoring(server.getPort());
        
        server.awaitTermination();
    }
    
    private static void startAdminServiceMonitoring(int port) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        
        scheduler.scheduleAtFixedRate(() -> {
            try {
                // Monitor channelz data
                monitorChannelzData(port);
                
                // Monitor health status
                monitorHealthStatus(port);
                
            } catch (Exception e) {
                System.err.println("Monitoring error: " + e.getMessage());
            }
        }, 60, 60, TimeUnit.SECONDS); // Monitor every minute
    }
    
    private static void monitorChannelzData(int port) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", port)
            .usePlaintext()
            .build();
            
        try {
            ChannelzGrpc.ChannelzBlockingStub channelzStub = 
                ChannelzGrpc.newBlockingStub(channel);
            
            GetServersResponse response = channelzStub.getServers(
                GetServersRequest.newBuilder().setMaxResults(10).build());
            
            response.getServerList().forEach(server -> {
                ServerData data = server.getData();
                System.out.printf("Server calls: started=%d, succeeded=%d, failed=%d%n",
                    data.getCallsStarted(),
                    data.getCallsSucceeded(), 
                    data.getCallsFailed());
            });
            
        } finally {
            channel.shutdown();
        }
    }
    
    private static void monitorHealthStatus(int port) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", port)
            .usePlaintext()
            .build();
            
        try {
            HealthGrpc.HealthBlockingStub healthStub = 
                HealthGrpc.newBlockingStub(channel);
            
            HealthCheckResponse response = healthStub.check(
                HealthCheckRequest.newBuilder().setService("").build());
            
            System.out.println("Overall server health: " + response.getStatus());
            
        } finally {
            channel.shutdown();
        }
    }
}

Security Considerations

Admin services expose operational data and should be secured appropriately:

public class SecureAdminServer {
    
    public static void main(String[] args) throws Exception {
        // Check if admin services should be enabled
        boolean enableAdminServices = Boolean.parseBoolean(
            System.getProperty("enable.admin.services", "false"));
        
        ServerBuilder<?> serverBuilder = ServerBuilder.forPort(8080);
        
        if (enableAdminServices) {
            System.out.println("Admin services enabled - ensure proper network security");
            serverBuilder.addServices(AdminInterface.getStandardServices());
        } else {
            System.out.println("Admin services disabled for security");
        }
        
        Server server = serverBuilder
            .addService(new UserService())
            .build();
        
        server.start();
        server.awaitTermination();
    }
}

// Alternative: Admin services on separate port
public class SeparateAdminPortServer {
    
    public static void main(String[] args) throws Exception {
        // Main business server
        Server businessServer = ServerBuilder.forPort(8080)
            .addService(new UserService())
            .addService(new OrderService())
            .build();
        
        // Admin server on separate port (can be firewalled differently)
        Server adminServer = ServerBuilder.forPort(9090)
            .addServices(AdminInterface.getStandardServices())
            .build();
        
        businessServer.start();
        adminServer.start();
        
        System.out.println("Business server on port 8080");
        System.out.println("Admin server on port 9090");
        
        // Wait for both servers
        businessServer.awaitTermination();
        adminServer.awaitTermination();
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-grpc--grpc-services

docs

admin-services.md

binary-logging.md

channelz.md

health-checking.md

index.md

load-balancing.md

metrics.md

server-reflection.md

tile.json