Interface Service

  • All Known Subinterfaces:
    SessionStore
    All Known Implementing Classes:
    HikariService

    public interface Service
    A service participates in the application lifecycle.

    When the application starts, all services in the server registry will be notified. Similarly when the application stops.

    
     import ratpack.core.server.RatpackServer;
     import ratpack.core.server.ServerConfig;
     import ratpack.core.service.Service;
     import ratpack.core.service.StartEvent;
     import ratpack.core.service.StopEvent;
    
     import java.util.List;
     import java.util.LinkedList;
     import static org.junit.jupiter.api.Assertions.*;
    
     public class Example {
    
       static class RecordingService implements Service {
         public final List<String> events = new LinkedList<>();
    
         public void onStart(StartEvent event) {
           events.add("start");
         }
    
         public void onStop(StopEvent event) {
           events.add("stop");
         }
       }
    
       public static void main(String... args) throws Exception {
         RecordingService service = new RecordingService();
    
         RatpackServer server = RatpackServer.of(s -> s
           .serverConfig(ServerConfig.embedded())
           .registryOf(r -> r.add(service))
           .handler(r -> ctx -> ctx.render("ok"))
         );
    
         assertEquals("[]", service.events.toString());
         server.start();
         assertEquals("[start]", service.events.toString());
         server.reload();
         assertEquals("[start, stop, start]", service.events.toString());
         server.stop();
         assertEquals("[start, stop, start, stop]", service.events.toString());
       }
     }
     

    Ordering

    Services can be ordered by the DependsOn and ServiceDependencies mechanisms.

    Async services

    The onStart(ratpack.core.service.StartEvent) and onStop(ratpack.core.service.StopEvent) methods are always executed within a distinct Execution, for each service. This means that implementations of these methods are free to perform async ops (e.g. use the HTTP client, or block).

    
     import ratpack.core.server.RatpackServer;
     import ratpack.core.server.ServerConfig;
     import ratpack.core.service.Service;
     import ratpack.core.service.StartEvent;
     import ratpack.core.service.StopEvent;
     import ratpack.exec.Promise;
    
     import java.util.List;
     import java.util.LinkedList;
     import static org.junit.jupiter.api.Assertions.*;
    
     public class Example {
    
       static class RecordingService implements Service {
         public final List<String> events = new LinkedList<>();
    
         public void onStart(StartEvent event) {
           Promise.value("start").map(String::toUpperCase).then(events::add);
         }
    
         public void onStop(StopEvent event) {
           Promise.value("stop").map(String::toUpperCase).then(events::add);
         }
       }
    
       public static void main(String... args) throws Exception {
         RecordingService service = new RecordingService();
    
         RatpackServer server = RatpackServer.of(s -> s
           .serverConfig(ServerConfig.embedded())
           .registryOf(r -> r.add(service))
           .handler(r -> ctx -> ctx.render("ok"))
         );
    
         server.start();
         assertEquals("[START]", service.events.toString());
         server.stop();
         assertEquals("[START, STOP]", service.events.toString());
       }
     }
     

    There is no need to catch promise errors. An error handler for the execution is installed that effectively treats any exceptions as if they were thrown by the method.

    Relationship with “business-logic”

    This interface does need to be used for business-logic type services, unless such services need to participate in the application lifecycle. Even in such a case, it is generally better to decouple the business-logic type service from Ratpack (i.e. this interface) and have a Service implementation that drives the business-logic service.

    Accessing the server registry

    The event objects given to the start/stop methods provide access to the server registry. This can be used, for example, to get hold of a database connection that was added to the server registry as part of the server definition.

    Alternatively, when using the Guice support the service can be injected by Guice.

    
     import ratpack.core.server.RatpackServer;
     import ratpack.core.server.ServerConfig;
     import ratpack.core.service.Service;
     import ratpack.core.service.StartEvent;
     import ratpack.core.service.StopEvent;
     import ratpack.guice.Guice;
     import ratpack.func.Types;
     import javax.inject.Inject;
    
     import java.util.List;
     import java.util.LinkedList;
     import static org.junit.jupiter.api.Assertions.*;
    
     public class Example {
    
       static class RecordingService implements Service {
         public final List<String> events;
    
         @Inject
         public RecordingService(List<String> events) {
           this.events = events;
         }
    
         public void onStart(StartEvent event) {
           events.add("start");
         }
    
         public void onStop(StopEvent event) {
           events.add("stop");
         }
       }
    
       public static void main(String... args) throws Exception {
         List<String> list = new LinkedList<>();
    
         RatpackServer server = RatpackServer.of(s -> s
           .serverConfig(ServerConfig.embedded())
           .registry(Guice.registry(b -> b
             .bindInstance(Types.listOf(String.class), list)
             .bind(RecordingService.class)
           ))
           .handler(r -> ctx -> ctx.render("ok"))
         );
    
         server.start();
         assertEquals("[start]", list.toString());
         server.stop();
         assertEquals("[start, stop]", list.toString());
       }
     }
     

    Errors

    If an onStart method errors, it will prevent the “application” from launching. In development mode, the application will start and display the error page for all requests with the error. When not in development mode, the exception will be thrown from the RatpackServer.start() method. If starting the app in a “main method”, this will prevent the JVM from starting.

    If an onStop method errors, the error will be logged and then the next service invoked. That is, a failed onStop method is not considered fatal.

    When a startup failure occurs, the server effectively shuts down which includes executing all the onStop methods.

    Since:
    1.3
    • Method Detail

      • getName

        default String getName()
        The name of this service, used for display purposes.

        The default implementation is to return getClass().getName().

        Returns:
        the name of this service, used for display purposes
      • onStart

        @NonBlocking
        default void onStart​(StartEvent event)
                      throws Exception
        Server startup event. Executed after the root registry and server instance are constructed and before the server begins accepting requests.
        Parameters:
        event - meta information about the startup event
        Throws:
        Exception - any
      • onStop

        @NonBlocking
        default void onStop​(StopEvent event)
                     throws Exception
        Server stop event. Executed after the root handler stops accepting requests and before the server closes the channel and thread pool.
        Parameters:
        event - meta information about the stop event
        Throws:
        Exception - any
      • startup

        static Service startup​(String name,
                               Action<? super StartEvent> action)
        Creates a service that executes the given action as the onStart(StartEvent) implementation.

        This can be used to create a service implementation from a lambda expression, instead of creating an anonymous impl of Service.

        Parameters:
        name - the name of the service
        action - the action to execute on start
        Returns:
        the service implementation
        Since:
        1.4
      • shutdown

        static Service shutdown​(String name,
                                Action<? super StopEvent> action)
        Creates a service that executes the given action as the onStop(StopEvent) implementation.

        This can be used to of a service implementation from a lambda expression, instead of creating an anonymous impl of Service.

        Parameters:
        name - the name of the service
        action - the action to execute on stop
        Returns:
        the service implementation
        Since:
        1.4