MarginaliaSearch/code/common/service-discovery
Viktor Lofgren 07b625c58d (query-client) Add support for fault-tolerant requests to single node services
Adding a method importantCall that will retry a failing request on each route until it succeeds or the routes run out.
2024-02-20 14:16:05 +01:00
..
src (query-client) Add support for fault-tolerant requests to single node services 2024-02-20 14:16:05 +01:00
build.gradle (refac) Zookeeper for service-discovery, kill service-client lib (WIP) 2024-02-20 11:41:14 +01:00
readme.md (refac) Zookeeper for service-discovery, kill service-client lib (WIP) 2024-02-20 11:41:14 +01:00

Service Discovery

Contains classes for helping services discover each other, and managing connections between them.

Service Registry

The service registry is a class that keeps track of the services that are currently running, and their connection information.

There are two implementations:

  • A simple implementation that effectively hard-codes the services. This is sufficient when running in docker, although loses some smart features. It is fundamentally incompatible with running the system bare-metal, and does not permit multiple instances of a service to run.

  • A more advanced implementation that is based on Zookeeper, which is a distributed coordination service. This implementation lets services register themselves and announce their liveness, and then discover each other. It supports multiple instances of a service running, and supports running the system bare-metal, where it will assign ports to the services from a range.

To be discoverable, the caller must first register their services:

// Register one or more services
registry.registerService(ApiSchema.GRPC,
                         ServiceId.Test,  
                         nodeId, 
                         instanceUUID, //must be unique to the runtime
                         "127.0.0.1"); // bind-address
// (+ any other services)

Then, the caller must announce their instance. Before this is done, the service is not discoverable.

registry.announceInstance(ServiceId.Test,
                          nodeId,
                          instanceUUID);

All of this is done automatically by the Service base class in the service module.

To discover a service, the caller can query the registry:

Set<InstanceAddress<?>> endpoints = registry.getEndpoints(ApiSchema.GRPC, ServiceId.Test, nodeId);

for (var endpoint : endpoints) {
    System.out.println(endpoint.getHost() + ":" + endpoint.getPort());
}

It's also possible to subscribe to changes in the registry, so that the caller can be notified when a service comes or goes, with registry.registerMonitor().

gRPC Channel Pool

From the GrpcChannelPoolFactory, two types of channel pools can be created that are aware of the service registry:

  • GrpcMultiNodeChannelPool - This pool permits 1-n style communication with partitioned services
  • GrpcSingleNodeChannelPool - This pool permits 1-1 style communication with non-partitioned services

The pools manage the lifecycle of the gRPC channels, and will permit the caller to access Stub interfaces for the services.

Central Classes

Service Registry

gRPC Channel Pool