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
andServiceDependencies
mechanisms.Async services
The
onStart(ratpack.core.service.StartEvent)
andonStop(ratpack.core.service.StopEvent)
methods are always executed within a distinctExecution
, for each service. This means that implementations of these methods are free to perform async ops (e.g. use theHTTP client
, orblock
).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. Indevelopment 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 theRatpackServer.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 failedonStop
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 Summary
All Methods Static Methods Instance Methods Default Methods Modifier and Type Method Description default String
getName()
The name of this service, used for display purposes.default void
onStart(StartEvent event)
Server startup event.default void
onStop(StopEvent event)
Server stop event.static Service
shutdown(String name, Action<? super StopEvent> action)
Creates a service that executes the given action as theonStop(StopEvent)
implementation.static Service
startup(String name, Action<? super StartEvent> action)
Creates a service that executes the given action as theonStart(StartEvent)
implementation.
-
-
-
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 theonStart(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 serviceaction
- 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 theonStop(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 serviceaction
- the action to execute on stop- Returns:
- the service implementation
- Since:
- 1.4
-
-