Skip to content

Commit c46100d

Browse files
authored
Merge pull request #42535 from holly-cummins/dev-service-docs
Add "how to write dev services" documentation
2 parents 601a2fa + 3386f3a commit c46100d

13 files changed

+141
-12
lines changed

docs/src/main/asciidoc/cache-redis-reference.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ include::{includes}/extension-status.adoc[]
2020

2121
When using Redis as the backend for Quarkus cache, each cached item will be stored in Redis:
2222

23-
- The backend uses the _<default>_ Redis client (if not configured otherwise), so make sure it's configured (or use the xref:redis-dev-services.adoc[redis dev service])
23+
- The backend uses the _<default>_ Redis client (if not configured otherwise), so make sure it's configured (or use the xref:redis-dev-services.adoc[Redis Dev Service])
2424
- the Redis key is built as follows: `cache:$cache-name:$cache-key`, where `cache-key` is the key the application uses.
2525
- the value is encoded to JSON if needed
2626

docs/src/main/asciidoc/databases-dev-services.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ quarkus.datasource.db-kind=mysql
166166
quarkus.datasource.devservices.volumes."/local/test/data"=/var/lib/mysql
167167
----
168168

169-
When starting Dev Services (for example, in tests or in dev mode), you will see that the folder "/local/test/data" will be created at your file sytem and that will contain all the database data. When rerunning again the same dev services, this data will contain all the data you might have created beforehand.
169+
When starting Dev Services (for example, in tests or in dev mode), you will see that the folder "/local/test/data" will be created at your file sytem and that will contain all the database data. When rerunning again the same Dev Services, this data will contain all the data you might have created beforehand.
170170

171171
[IMPORTANT]
172172
====
@@ -190,7 +190,7 @@ Overriding the MariaDB/MySQL configuration would be done as follows:
190190
quarkus.datasource.devservices.container-properties.TC_MY_CNF=testcontainers/mysql-conf
191191
----
192192

193-
This support is database specific and needs to be implemented in each dev service specifically.
193+
This support is database specific and needs to be implemented in each Dev Service specifically.
194194

195195
== Connect To Database Run as a Dev Service
196196

docs/src/main/asciidoc/dev-services.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
66
= Dev Services Overview
77
include::_attributes.adoc[]
88
:categories: core
9-
:summary: An introduction to dev services and a list of all extensions that support Dev Services and their configuration options.
9+
:summary: An introduction to Dev Services and a list of all extensions that support Dev Services and their configuration options.
1010
:topics: dev-services,dev-mode,testing
1111

1212
== What Are Dev Services?
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
////
2+
This document is maintained in the main Quarkus repository
3+
and pull requests should be submitted there:
4+
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
5+
////
6+
[id="extension-writing-dev-service"]
7+
= Writing a Dev Service
8+
include::_attributes.adoc[]
9+
:categories: writing-extensions
10+
:diataxis-type: howto
11+
:topics: extensions
12+
////
13+
////
14+
15+
16+
== Prerequisites
17+
18+
- You should already have an xref:building-my-first-extension.adoc[extension structure] in place
19+
- You should have a containerised version of your external service (not all Dev Services rely on containers, but most do)
20+
21+
== Creating a Dev Service
22+
23+
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.
24+
25+
To create a Dev Service, add a new build step into the extension processor class that returns a `DevServicesResultBuildItem`.
26+
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.
27+
28+
[source%nowrap,java]
29+
----
30+
@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) {
31+
public DevServicesResultBuildItem createContainer() {
32+
DockerImageName dockerImageName = DockerImageName.parse("hello-world");
33+
GenericContainer container = new GenericContainer<>(dockerImageName)
34+
.withExposedPorts(SERVICE_PORT, OTHER_SERVICE_PORT)
35+
.waitingFor(Wait.forLogMessage(".*" + "Started" + ".*", 1))
36+
.withReuse(true);
37+
38+
container.start();
39+
40+
String newUrl = "http://" + container.getHost() + ":" + container.getMappedPort(SERVICE_PORT);
41+
Map<String, String> configOverrides = Map.of("some-service.base-url", newUrl);
42+
43+
return new DevServicesResultBuildItem.RunningDevService(FEATURE, container.getContainerId(),
44+
container::close, configOverrides)
45+
.toBuildItem();
46+
}
47+
----
48+
49+
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`.
50+
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.
51+
For example,
52+
53+
[source%nowrap,java]
54+
----
55+
GenericContainer container = new GenericContainer<>(dockerImageName)
56+
.withExposedPorts(SERVICE_PORT, OTHER_SERVICE_PORT);
57+
----
58+
59+
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?
60+
61+
To allow applications to connect, the extension should override the default configuration for the service with the mapped ports.
62+
This must be done after starting the container.
63+
For example,
64+
65+
[source%nowrap,java]
66+
----
67+
container.start();
68+
Map<String, String> configOverrides = Map.of("some-service.base-url",
69+
"http://" + container.getHost() + ":" + container.getMappedPort(SERVICE_PORT));
70+
----
71+
72+
Other configuration overrides may be included in the same map.
73+
74+
== Waiting for the container to start
75+
76+
You should add a `.waitingFor` call to the container construction, to wait for the container to start. For example
77+
78+
[source%nowrap,java]
79+
----
80+
.waitingFor(Wait.forLogMessage(".*" + "Started" + ".*", 1))
81+
----
82+
83+
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.
84+
85+
== Configuring the Dev Service
86+
87+
To configure the Dev Service launch process, your build step can accept a `ConfigPhase.BUILD_TIME` config class in its constructor.
88+
For example,
89+
90+
[source%nowrap,java]
91+
----
92+
@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) {
93+
public DevServicesResultBuildItem createContainer(MyConfig config) {
94+
----
95+
96+
You may wish to use this config to set a fixed port, or set an image name, for example.
97+
98+
[source%nowrap,java]
99+
----
100+
if (config.port.isPresent()) {
101+
container.setPortBindings(List.of(config.port.get() + ":" + SERVICE_PORT));
102+
}
103+
----
104+
105+
== Controlling re-use
106+
107+
In dev mode, with live reload, Quarkus may restart frequently. By default, this will also restart test containers.
108+
Quarkus restarts are usually very fast, but containers may take much longer to restart.
109+
To prevent containers restarting on every code change, you can mark the container as reusable:
110+
111+
[source%nowrap,java]
112+
----
113+
.withReuse(true)
114+
----
115+
116+
Some Dev Services implement sophisticated reuse logic in which they track the state of the container in the processor itself.
117+
You may need this if your service has more complex requirements, or needs sharing across instances.
118+
119+
120+
== References
121+
122+
- xref:dev-services.adoc[Dev services overview]
123+
- xref:writing-extensions.adoc[Guide to writing extensions]

docs/src/main/asciidoc/getting-started-dev-services.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ But what about production? You won't want to use Dev Services in production.
306306
In fact, Quarkus only starts Dev Services in dev and test modes.
307307

308308
Wouldn't it be nice to configure an external database,
309-
but have it *only* used in production, so you could still use dev services the rest of the time?
309+
but have it *only* used in production, so you could still use Dev Services the rest of the time?
310310

311311
Add a `%prod.`
312312
prefix to the database configuration. This means the configuration

docs/src/main/asciidoc/getting-started.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ include::{generated-dir}/config/quarkus-info.adoc[opts=optional, leveloffset=+2]
491491

492492
This guide covered the creation of an application using Quarkus.
493493
However, there is much more.
494-
We recommend continuing the journey by creating xref:getting-started-dev-services.adoc[your second Quarkus application], with dev services and persistence.
494+
We recommend continuing the journey by creating xref:getting-started-dev-services.adoc[your second Quarkus application], with Dev Services and persistence.
495495
You can learn about creating a native executable and packaging it in a container with the xref:building-native-image.adoc[building a native executable guide].
496496
If you are interested in reactive, we recommend the xref:getting-started-reactive.adoc[getting started with reactive guide], where you can see how to implement reactive applications with Quarkus.
497497

docs/src/main/asciidoc/infinispan-dev-services.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ link:https://infinispan.org/tutorials/simple/simple_tutorials.html#cross-site-re
108108

109109
== Multiple Dev Services for named connections
110110
The Infinispan Client extension supports connecting to more than one Infinispan Cluster with
111-
the named connections. If you need to spin an additional dev service for a connection name, configure
111+
the named connections. If you need to spin an additional Dev Service for a connection name, configure
112112
at least on property in the application properties:
113113

114114
[source,properties]

docs/src/main/asciidoc/kafka-dev-services.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Dev Services for Kafka supports https://redpanda.com[Redpanda], https://github/o
5656
and https://strimzi.io[Strimzi] (in https://github.com/apache/kafka/blob/trunk/config/kraft/README.md[Kraft] mode) images.
5757

5858
**Redpanda** is a Kafka compatible event streaming platform.
59-
Because it provides a fast startup times, dev services defaults to Redpanda images from `vectorized/redpanda`.
59+
Because it provides a fast startup times, Dev Services defaults to Redpanda images from `vectorized/redpanda`.
6060
You can select any version from https://hub.docker.com/r/vectorized/redpanda.
6161

6262
**kafka-native** provides images of standard Apache Kafka distribution compiled to native binary using Quarkus and GraalVM.

docs/src/main/asciidoc/kafka-schema-registry-avro.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ The `quarkus-apicurio-registry-avro` extension depends on recent versions of Api
620620
and most versions of Apicurio Registry server and client are backwards compatible.
621621
For some you need to make sure that the client used by Serdes is compatible with the server.
622622

623-
For example, with Apicurio dev service if you set the image name to use version `2.1.5.Final`:
623+
For example, with Apicurio Dev Service if you set the image name to use version `2.1.5.Final`:
624624

625625
[source,properties]
626626
----

docs/src/main/asciidoc/kafka-schema-registry-json-schema.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ The `quarkus-apicurio-registry-json-schema` extension depends on recent versions
648648
and most versions of Apicurio Registry server and client are backwards compatible.
649649
For some you need to make sure that the client used by Serdes is compatible with the server.
650650

651-
For example, with Apicurio dev service if you set the image name to use version `2.1.5.Final`:
651+
For example, with Apicurio Dev Service if you set the image name to use version `2.1.5.Final`:
652652

653653
[source,properties]
654654
----

0 commit comments

Comments
 (0)