public interface Service
When the application starts, all services in the server registry will be notified. Similarly when the application stops.
import ratpack.server.RatpackServer;
import ratpack.server.ServerConfig;
import ratpack.service.Service;
import ratpack.service.StartEvent;
import ratpack.service.StopEvent;
import java.util.List;
import java.util.LinkedList;
import static org.junit.Assert.*;
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());
}
}
Services can be ordered by the DependsOn
and ServiceDependencies
mechanisms.
The onStart(ratpack.service.StartEvent)
and onStop(ratpack.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.server.RatpackServer;
import ratpack.server.ServerConfig;
import ratpack.service.Service;
import ratpack.service.StartEvent;
import ratpack.service.StopEvent;
import ratpack.exec.Promise;
import java.util.List;
import java.util.LinkedList;
import static org.junit.Assert.*;
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.
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.
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.server.RatpackServer;
import ratpack.server.ServerConfig;
import ratpack.service.Service;
import ratpack.service.StartEvent;
import ratpack.service.StopEvent;
import ratpack.guice.Guice;
import ratpack.util.Types;
import javax.inject.Inject;
import java.util.List;
import java.util.LinkedList;
import static org.junit.Assert.*;
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());
}
}
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.
Modifier and Type | Method and Description |
---|---|
default java.lang.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(java.lang.String name,
Action<? super StopEvent> action)
Creates a service that executes the given action as the
onStop(StopEvent) implementation. |
static Service |
startup(java.lang.String name,
Action<? super StartEvent> action)
Creates a service that executes the given action as the
onStart(StartEvent) implementation. |
default java.lang.String getName()
The default implementation is to return getClass().getName()
.
@NonBlocking default void onStart(StartEvent event) throws java.lang.Exception
event
- meta information about the startup eventjava.lang.Exception
- any@NonBlocking default void onStop(StopEvent event) throws java.lang.Exception
event
- meta information about the stop eventjava.lang.Exception
- anystatic Service startup(java.lang.String name, Action<? super StartEvent> action)
onStart(StartEvent)
implementation.
This can be used to create a service implementation from a lambda expression,
instead of creating an anonymous impl of Service
.
name
- the name of the serviceaction
- the action to execute on startstatic Service shutdown(java.lang.String name, Action<? super StopEvent> action)
onStop(StopEvent)
implementation.
This can be used to of a service implementation from a lambda expression,
instead of creating an anonymous impl of Service
.
name
- the name of the serviceaction
- the action to execute on stop