-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
//// | ||
This document is maintained in the main Quarkus repository | ||
and pull requests should be submitted there: | ||
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc | ||
//// | ||
[id="extension-writing-dev-service"] | ||
= Writing a dev service | ||
include::_attributes.adoc[] | ||
:categories: writing-extensions | ||
:diataxis-type: howto | ||
:topics: extensions | ||
//// | ||
//// | ||
|
||
|
||
== Prerequisites | ||
|
||
- You should already have an xref:building-my-first-extension.adoc[extension structure] in place | ||
- You should have a containerised version of your external service (not all dev services rely on containers, but most do) | ||
|
||
== Creating a dev service | ||
|
||
If your extension provides APIs for connecting to an external service, it's a good idea to provide a xref:dev-services.adoc[dev service] implementation. | ||
|
||
To create a dev service, add a new build step into the extension processor class that returns a `DevServicesResultBuildItem`. | ||
Here, the link:https://hub.docker.com/_/hello-world`hello-world` image is used, but you should set up the right image for your service. | ||
|
||
[source%nowrap,java] | ||
---- | ||
@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) { | ||
public DevServicesResultBuildItem createContainer() { | ||
DockerImageName dockerImageName = DockerImageName.parse("hello-world"); | ||
GenericContainer container = new GenericContainer<>(dockerImageName) | ||
.withExposedPorts(SERVICE_PORT, OTHER_SERVICE_PORT) | ||
.waitingFor(Wait.forLogMessage(".*" + "Started" + ".*", 1)) | ||
.withReuse(true); | ||
container.start(); | ||
String newUrl = "http://" + container.getHost() + ":" + container.getMappedPort(SERVICE_PORT); | ||
Map<String, String> configOverrides = Map.of("some-service.base-url", newUrl); | ||
return new DevServicesResultBuildItem.RunningDevService(FEATURE, container.getContainerId(), | ||
container::close, configOverrides) | ||
.toBuildItem(); | ||
} | ||
---- | ||
|
||
With this code, you should be able to see your container starting if you add your extension to a test application and run `quarkus dev`. | ||
However, the application will not be able to connect to it, because no ports are exposed. To expose ports, add `withExposedPorts` to the container construction. | ||
For example, | ||
|
||
[source%nowrap,java] | ||
---- | ||
GenericContainer container = new GenericContainer<>(dockerImageName) | ||
.withExposedPorts(SERVICE_PORT, OTHER_SERVICE_PORT); | ||
---- | ||
|
||
Testcontainers will map these ports to random ports on the host. This avoids port conflicts, but presents a new problem – how do applications connect to the service in the container? | ||
Check warning on line 59 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
|
||
To allow applications to connect, the extension should override the default configuration for the service with the mapped ports. | ||
This must be done after starting the container. | ||
For example, | ||
|
||
[source%nowrap,java] | ||
---- | ||
container.start(); | ||
Map<String, String> configOverrides = Map.of("some-service.base-url", | ||
"http://" + container.getHost() + ":" + container.getMappedPort(SERVICE_PORT)); | ||
---- | ||
|
||
Other configuration overrides may be included in the same map. | ||
Check warning on line 72 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
|
||
== Waiting for the container to start | ||
|
||
You should add a `.waitingFor` call to the container construction, to wait for the container to start. For example | ||
|
||
[source%nowrap,java] | ||
---- | ||
.waitingFor(Wait.forLogMessage(".*" + "Started" + ".*", 1)) | ||
---- | ||
|
||
Waiting for a port to be open is another option. See the link:https://java.testcontainers.org/features/startup_and_waits/[Testcontainers documentation] for a full discussion of wait strategies. | ||
|
||
== Configuring the dev service | ||
|
||
To configure the dev service launch process, your build step can accept a `ConfigPhase.BUILD_TIME` config class in its constructor. | ||
Check warning on line 87 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
For example, | ||
|
||
[source%nowrap,java] | ||
---- | ||
@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) { | ||
public DevServicesResultBuildItem createContainer(MyConfig config) { | ||
---- | ||
|
||
You may wish to use this config to set a fixed port, or set an image name, for example. | ||
Check warning on line 96 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
Check warning on line 96 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
|
||
[source%nowrap,java] | ||
---- | ||
if (config.port.isPresent()) { | ||
container.setPortBindings(List.of(config.port.get() + ":" + SERVICE_PORT)); | ||
} | ||
---- | ||
|
||
== Controlling re-use | ||
|
||
In dev mode, with hot reload, Quarkus may restart frequently. By default, this will also restart test containers. | ||
Check warning on line 107 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
Quarkus restarts are usually very fast, but containers may take much longer to restart. | ||
Check warning on line 108 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
To prevent containers restarting on every code change, you can mark the container as reusable: | ||
Check warning on line 109 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
|
||
[source%nowrap,java] | ||
---- | ||
.withReuse(true) | ||
---- | ||
|
||
Some dev services implement sophisticated reuse logic in which they track the state of the container in the processor itself. | ||
You may need this if your service has more complex requirements, or needs sharing across instances. | ||
Check warning on line 117 in docs/src/main/asciidoc/extension-writing-dev-service.adoc GitHub Actions / Linting with Vale
|
||
|
||
|
||
== References | ||
|
||
- xref:dev-services.adoc[Dev services overview] | ||
- xref:writing-extensions.adoc[Guide to writing extensions] |