Service remoting in Java with Reliable Services
For services that aren't tied to a particular communication protocol or stack, such as WebAPI, Windows Communication Foundation (WCF), or others, the Reliable Services framework provides a remoting mechanism to quickly and easily set up remote procedure calls for services. This article discusses how to set up remote procedure calls for services written with Java.
Set up remoting on a service
Setting up remoting for a service is done in two simple steps:
- Create an interface for your service to implement. This interface defines the methods that are available for a remote procedure call on your service. The methods must be task-returning asynchronous methods. The interface must implement
microsoft.serviceFabric.services.remoting.Service
to signal that the service has a remoting interface. - Use a remoting listener in your service. This is an
CommunicationListener
implementation that provides remoting capabilities.FabricTransportServiceRemotingListener
can be used to create a remoting listener using the default remoting transport protocol.
For example, the following stateless service exposes a single method to get "Hello World" over a remote procedure call.
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.List;
import microsoft.servicefabric.services.communication.runtime.ServiceInstanceListener;
import microsoft.servicefabric.services.remoting.Service;
import microsoft.servicefabric.services.runtime.StatelessService;
public interface MyService extends Service {
CompletableFuture<String> helloWorldAsync();
}
class MyServiceImpl extends StatelessService implements MyService {
public MyServiceImpl(StatelessServiceContext context) {
super(context);
}
public CompletableFuture<String> helloWorldAsync() {
return CompletableFuture.completedFuture("Hello!");
}
@Override
protected List<ServiceInstanceListener> createServiceInstanceListeners() {
ArrayList<ServiceInstanceListener> listeners = new ArrayList<>();
listeners.add(new ServiceInstanceListener((context) -> {
return new FabricTransportServiceRemotingListener(context,this);
}));
return listeners;
}
}
Note
The arguments and the return types in the service interface can be any simple, complex, or custom types, but they must be serializable.
Call remote service methods
Calling methods on a service by using the remoting stack is done by using a local proxy to the service through the microsoft.serviceFabric.services.remoting.client.ServiceProxyBase
class. The ServiceProxyBase
method creates a local proxy by using the same interface that the service implements. With that proxy, you can simply call methods on the interface remotely.
MyService helloWorldClient = ServiceProxyBase.create(MyService.class, new URI("fabric:/MyApplication/MyHelloWorldService"));
CompletableFuture<String> message = helloWorldClient.helloWorldAsync();
The remoting framework propagates exceptions thrown at the service to the client. So exception-handling logic at the client by using ServiceProxyBase
can directly handle exceptions that the service throws.
Service Proxy Lifetime
ServiceProxy creation is a lightweight operation, so you can create as many as you need. Service Proxy instances can be reused as long as they are needed. If a remote procedure call throws an Exception, you can still reuse the same proxy instance. Each ServiceProxy contains a communication client used to send messages over the wire. While invoking remote calls, internal checks are performed to determine if the communication client is valid. Based on the results of those checks, the communication client is recreated if needed. Therefore, if an exception occurs, you do not need to recreate ServiceProxy
.
ServiceProxyFactory Lifetime
FabricServiceProxyFactory is a factory that creates proxy for different remoting interfaces. If you use API ServiceProxyBase.create
for creating proxy, then framework creates a FabricServiceProxyFactory
.
It is useful to create one manually when you need to override ServiceRemotingClientFactory properties.
Factory is an expensive operation. FabricServiceProxyFactory
maintains cache of communication clients.
Best practice is to cache FabricServiceProxyFactory
for as long as possible.
Remoting Exception Handling
All the remote exception thrown by service API, are sent back to the client either as RuntimeException or FabricException.
ServiceProxy does handle all Failover Exception for the service partition it is created for. It re-resolves the endpoints if there is Failover Exceptions(Non-Transient Exceptions) and retries the call with the correct endpoint. Number of retries for failover Exception is indefinite. In case of TransientExceptions, it only retries the call.
Default retry parameters are provied by OperationRetrySettings. You can configure these values by passing OperationRetrySettings object to ServiceProxyFactory constructor.