Skip to content

Commit c36fec8

Browse files
authored
Merge pull request #48815 from holly-cummins/ephemeral-ports-in-lambdas
Fix dev service ephemeral ports: Make test resource config override dev service config and system props
2 parents 8657c26 + 296c455 commit c36fec8

File tree

14 files changed

+210
-48
lines changed

14 files changed

+210
-48
lines changed

core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesRegistryBuildItem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ private void reallyStart(DevServicesResultBuildItem request, List<DevServicesCus
125125
startable.start();
126126

127127
RunningService service = new RunningService(request.getName(), request.getDescription(),
128-
request.getConfig(startable), startable.getContainerId(), startable);
128+
request.getConfig(startable), request.getOverrideConfig(startable), startable.getContainerId(), startable);
129129
this.addRunningService(request.getName(), request.getServiceName(), request.getServiceConfig(), service);
130130

131131
compressor.close();

core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesResultBuildItem.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.HashMap;
77
import java.util.Map;
88
import java.util.Objects;
9+
import java.util.Set;
910
import java.util.function.Consumer;
1011
import java.util.function.Function;
1112
import java.util.function.Supplier;
@@ -77,6 +78,7 @@ public final class DevServicesResultBuildItem extends MultiBuildItem {
7778
* A map of application config that is dependent on the started service
7879
*/
7980
private final Map<String, Function<Startable, String>> applicationConfigProvider;
81+
private final Set<String> highPriorityConfig;
8082

8183
public static DiscoveredServiceBuilder discovered() {
8284
return new DiscoveredServiceBuilder();
@@ -106,6 +108,7 @@ public DevServicesResultBuildItem(String name, String description, String contai
106108
this.serviceName = null;
107109
this.serviceConfig = null;
108110
this.applicationConfigProvider = null;
111+
this.highPriorityConfig = null;
109112
this.startableSupplier = null;
110113
this.postStartAction = null;
111114
}
@@ -121,7 +124,7 @@ public DevServicesResultBuildItem(String name,
121124
Map<String, String> config,
122125
Supplier<Startable> startableSupplier,
123126
Consumer<Startable> postStartAction,
124-
Map<String, Function<Startable, String>> applicationConfigProvider) {
127+
Map<String, Function<Startable, String>> applicationConfigProvider, Set<String> highPriorityConfig) {
125128
this.name = name;
126129
this.description = description;
127130
this.containerId = null;
@@ -131,6 +134,7 @@ public DevServicesResultBuildItem(String name,
131134
this.startableSupplier = startableSupplier;
132135
this.postStartAction = postStartAction;
133136
this.applicationConfigProvider = applicationConfigProvider;
137+
this.highPriorityConfig = highPriorityConfig;
134138
}
135139

136140
public String getName() {
@@ -175,6 +179,7 @@ public Map<String, Function<Startable, String>> getApplicationConfigProvider() {
175179

176180
public Map<String, String> getConfig(Startable startable) {
177181
SupplierMap<String, String> map = new SupplierMap<>();
182+
// To make sure static config does make it into a config source, include it here
178183
if (config != null && !config.isEmpty()) {
179184
map.putAll(config);
180185
}
@@ -186,6 +191,22 @@ public Map<String, String> getConfig(Startable startable) {
186191
return map;
187192
}
188193

194+
/**
195+
* @deprecated Subject to changes due to <a href="https://github.com/quarkusio/quarkus/pull/51209">#51209</a>
196+
*/
197+
@Deprecated(forRemoval = true)
198+
public Map<String, String> getOverrideConfig(Startable startable) {
199+
200+
SupplierMap<String, String> map = new SupplierMap<>();
201+
202+
if (highPriorityConfig != null) {
203+
for (String key : highPriorityConfig) {
204+
map.put(key, () -> applicationConfigProvider.get(key).apply(startable));
205+
}
206+
}
207+
return map;
208+
}
209+
189210
public static class DiscoveredServiceBuilder {
190211
private String name;
191212
private String containerId;
@@ -226,10 +247,8 @@ public DevServicesResultBuildItem build() {
226247
}
227248

228249
public static class OwnedServiceBuilder<T extends Startable> {
229-
230250
private static final String IO_QUARKUS_DEVSERVICES_CONFIG_BUILDER_CLASS = "io.quarkus.devservice.runtime.config.DevServicesConfigBuilder";
231-
private static final boolean CONFIG_BUILDER_AVAILABLE = isClassAvailable(
232-
IO_QUARKUS_DEVSERVICES_CONFIG_BUILDER_CLASS);
251+
private static final boolean CONFIG_BUILDER_AVAILABLE = isClassAvailable(IO_QUARKUS_DEVSERVICES_CONFIG_BUILDER_CLASS);
233252

234253
private String name;
235254
private String description;
@@ -239,6 +258,7 @@ public static class OwnedServiceBuilder<T extends Startable> {
239258
private Supplier<? extends Startable> startableSupplier;
240259
private Consumer<? extends Startable> postStartAction;
241260
private Map<String, Function<Startable, String>> applicationConfigProvider;
261+
private Set<String> highPriorityConfig;
242262

243263
public OwnedServiceBuilder<T> name(String name) {
244264
this.name = name;
@@ -286,6 +306,15 @@ public OwnedServiceBuilder<T> postStartHook(Consumer<T> postStartAction) {
286306
return this;
287307
}
288308

309+
/**
310+
* @deprecated Subject to changes due to <a href="https://github.com/quarkusio/quarkus/pull/51209">#51209</a>
311+
*/
312+
@Deprecated(forRemoval = true)
313+
public OwnedServiceBuilder<T> highPriorityConfig(Set<String> highPriorityConfig) {
314+
this.highPriorityConfig = highPriorityConfig;
315+
return this;
316+
}
317+
289318
/**
290319
* Provides config to inject into the config system. If you've got values that don't change, use config(), and if you've
291320
* got values that you'll only know after starting the container, use configProvider() and provide a map of
@@ -306,7 +335,7 @@ public DevServicesResultBuildItem build() {
306335
return new DevServicesResultBuildItem(name, description, serviceName, serviceConfig, config,
307336
(Supplier<Startable>) startableSupplier,
308337
(Consumer<Startable>) postStartAction,
309-
applicationConfigProvider);
338+
applicationConfigProvider, highPriorityConfig);
310339
}
311340

312341
private static boolean isClassAvailable(String className) {

core/runtime/src/main/java/io/quarkus/devservices/crossclassloader/runtime/RunningService.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ public final class RunningService implements Closeable {
1616
private final String feature;
1717
private final String description;
1818
private final Map<String, String> configs;
19+
private final Map<String, String> overrideConfigs;
1920
private final String containerId;
2021
private final Closeable closeable;
2122

22-
public RunningService(String feature, String description, Map<String, String> configs, String containerId,
23+
public RunningService(String feature, String description, Map<String, String> configs, Map<String, String> overrideConfig,
24+
String containerId,
2325
Closeable closeable) {
2426
this.feature = feature;
2527
this.description = description;
2628
this.configs = configs;
29+
this.overrideConfigs = overrideConfig;
2730
this.containerId = containerId;
2831
this.closeable = closeable;
2932
}
@@ -45,8 +48,15 @@ public Map<String, String> configs() {
4548
return configs;
4649
}
4750

51+
/**
52+
* @deprecated Subject to changes due to <a href="https://github.com/quarkusio/quarkus/pull/51209">#51209</a>
53+
*/
54+
@Deprecated(forRemoval = true)
55+
public Map<String, String> overrideConfigs() {
56+
return overrideConfigs;
57+
}
58+
4859
public String containerId() {
4960
return containerId;
5061
}
51-
5262
}

extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
import java.io.IOException;
66
import java.util.Map;
77
import java.util.Optional;
8+
import java.util.Set;
89

10+
import org.eclipse.microprofile.config.ConfigProvider;
911
import org.jboss.logging.Logger;
1012

1113
import io.quarkus.amazon.lambda.runtime.AmazonLambdaApi;
1214
import io.quarkus.amazon.lambda.runtime.LambdaHotReplacementRecorder;
1315
import io.quarkus.amazon.lambda.runtime.MockEventServer;
16+
import io.quarkus.amazon.lambda.runtime.MockEventServerConfig;
1417
import io.quarkus.deployment.Feature;
1518
import io.quarkus.deployment.IsLiveReloadSupportedByLaunchMode;
1619
import io.quarkus.deployment.IsProduction;
@@ -51,7 +54,7 @@ private boolean legacyTestingEnabled() {
5154
@Produce(ServiceStartBuildItem.class)
5255
@BuildStep(onlyIfNot = IsProduction.class) // This is required for testing so run it even if devservices.enabled=false
5356
public void startEventServer(LaunchModeBuildItem launchModeBuildItem,
54-
LambdaConfig config,
57+
LambdaBuildConfig config,
5558
Optional<EventServerOverrideBuildItem> override,
5659
BuildProducer<DevServicesResultBuildItem> devServicePropertiesProducer) {
5760
LaunchMode launchMode = launchModeBuildItem.getLaunchMode();
@@ -70,18 +73,17 @@ public void startEventServer(LaunchModeBuildItem launchModeBuildItem,
7073
server = new MockEventServer();
7174
}
7275

73-
int configuredPort = launchMode == LaunchMode.TEST ? config.mockEventServer().testPort()
74-
: config.mockEventServer().devPort();
75-
String portPropertySuffix = launchMode == LaunchMode.TEST ? "test-port" : "dev-port";
76+
boolean isTest = launchMode == LaunchMode.TEST;
77+
String portPropertySuffix = isTest ? "test-port" : "dev-port";
7678
String propName = "quarkus.lambda.mock-event-server." + portPropertySuffix;
7779

7880
// No compose support, and no using of external services, so no need to discover existing services
7981

8082
DevServicesResultBuildItem buildItem = DevServicesResultBuildItem.owned().feature(Feature.AMAZON_LAMBDA)
8183
.serviceName(Feature.AMAZON_LAMBDA.getName())
8284
.serviceConfig(config)
83-
.startable(() -> new StartableEventServer(
84-
server, configuredPort))
85+
.startable(() -> new StartableEventServer(server, propName, isTest))
86+
.highPriorityConfig(Set.of(propName)) // Pass through the external config for the port, so that it can be overridden if it's an ephemeral port
8587
.configProvider(
8688
Map.of(propName, s -> String.valueOf(s.getExposedPort()),
8789
AmazonLambdaApi.QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API,
@@ -93,17 +95,26 @@ public void startEventServer(LaunchModeBuildItem launchModeBuildItem,
9395
}
9496

9597
private static class StartableEventServer implements Startable {
96-
9798
private final MockEventServer server;
98-
private final int configuredPort;
99+
private final String propName;
100+
private final boolean isTest;
99101

100-
public StartableEventServer(MockEventServer server, int configuredPort) {
102+
public StartableEventServer(MockEventServer server, String propName, boolean isTest) {
101103
this.server = server;
102-
this.configuredPort = configuredPort;
104+
this.propName = propName;
105+
this.isTest = isTest;
103106
}
104107

105108
@Override
106109
public void start() {
110+
// Technically, we shouldn't peek at the runtime config, but every dev service does it
111+
// However, we won't get defaults, so we need to fill our own in
112+
int port = isTest ? Integer.parseInt(MockEventServerConfig.TEST_PORT)
113+
: Integer.parseInt(MockEventServerConfig.DEV_PORT);
114+
int configuredPort = ConfigProvider.getConfig().getOptionalValue(propName, Integer.class)
115+
.or(() -> Optional.of(port))
116+
.get();
117+
107118
server.start(configuredPort);
108119
log.debugf("Starting event server on port %d", configuredPort);
109120
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.quarkus.amazon.lambda.deployment;
2+
3+
import io.quarkus.runtime.annotations.ConfigPhase;
4+
import io.quarkus.runtime.annotations.ConfigRoot;
5+
import io.smallrye.config.ConfigMapping;
6+
7+
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
8+
@ConfigMapping(prefix = "quarkus.lambda")
9+
public interface LambdaBuildConfig {
10+
11+
/**
12+
* Configuration for the mock event server that is run
13+
* in dev mode and test mode
14+
*/
15+
MockEventServerBuildConfig mockEventServer();
16+
}
Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,11 @@
66
* Configuration for the mock event server that is run
77
* in dev mode and test mode
88
*/
9-
public interface MockEventServerConfig {
9+
public interface MockEventServerBuildConfig {
1010
/**
1111
* Setting to true will start event server even if quarkus.devservices.enabled=false
1212
*/
1313
@WithDefault("true")
1414
boolean enabled();
1515

16-
/**
17-
* Port to access mock event server in dev mode
18-
*/
19-
@WithDefault("8080")
20-
int devPort();
21-
22-
/**
23-
* Port to access mock event server in dev mode
24-
*/
25-
@WithDefault("8081")
26-
int testPort();
2716
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
package io.quarkus.amazon.lambda.deployment;
1+
package io.quarkus.amazon.lambda.runtime;
22

33
import io.quarkus.runtime.annotations.ConfigPhase;
44
import io.quarkus.runtime.annotations.ConfigRoot;
55
import io.smallrye.config.ConfigMapping;
66

7-
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
7+
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
88
@ConfigMapping(prefix = "quarkus.lambda")
99
public interface LambdaConfig {
1010

@@ -13,4 +13,5 @@ public interface LambdaConfig {
1313
* in dev mode and test mode
1414
*/
1515
MockEventServerConfig mockEventServer();
16+
1617
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.quarkus.amazon.lambda.runtime;
2+
3+
import io.quarkus.runtime.annotations.ConfigPhase;
4+
import io.quarkus.runtime.annotations.ConfigRoot;
5+
import io.smallrye.config.ConfigMapping;
6+
import io.smallrye.config.WithDefault;
7+
8+
/**
9+
* Configuration for the mock event server that is run
10+
* in dev mode and test mode
11+
*/
12+
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
13+
@ConfigMapping(prefix = "quarkus.lambda")
14+
public interface MockEventServerConfig {
15+
static final String DEV_PORT = "8080";
16+
static final String TEST_PORT = "8081";
17+
18+
/**
19+
* Port to access mock event server in dev mode
20+
*/
21+
@WithDefault(DEV_PORT)
22+
int devPort();
23+
24+
/**
25+
* Port to access mock event server in dev mode
26+
*/
27+
@WithDefault(TEST_PORT)
28+
int testPort();
29+
}

extensions/devservices/deployment/src/main/java/io/quarkus/devservices/deployment/DevServicesProcessor.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,18 @@ DevServicesRegistryBuildItem devServicesRegistry(LaunchModeBuildItem launchMode,
154154

155155
// Because the devservices runtime module is new and the ecosystem needs time to catch up, don't die if the runtime module isn't available
156156
@BuildStep(onlyIf = { IsRuntimeModuleAvailable.class })
157-
public RunTimeConfigBuilderBuildItem registerDevResourcesConfigSource(
158-
List<DevServicesResultBuildItem> devServicesRequestBuildItems) {
157+
public void registerDevResourcesConfigSource(BuildProducer<RunTimeConfigBuilderBuildItem> runtimeConfigBuilders) {
159158
// Once all the dev services are registered, we can share config
160159
try {
161160
// Use reflection, since we don't have an explicit dependency on the runtime module (because dependent extensions may not have that dependency)
162-
Class<?> builderClass = Class
163-
.forName(IO_QUARKUS_DEVSERVICES_CONFIG_BUILDER_CLASS);
164-
return new RunTimeConfigBuilderBuildItem(builderClass);
161+
runtimeConfigBuilders
162+
.produce(new RunTimeConfigBuilderBuildItem(Class.forName(IO_QUARKUS_DEVSERVICES_CONFIG_BUILDER_CLASS)));
163+
runtimeConfigBuilders.produce(new RunTimeConfigBuilderBuildItem(
164+
Class.forName("io.quarkus.devservice.runtime.config.DevServicesOverrideConfigBuilder")));
165165
} catch (ClassNotFoundException e) {
166166
// Should never happen, because of the guard, as long as the runtime module is not a direct dependency of this module
167167
throw new RuntimeException(e);
168168
}
169-
170169
}
171170

172171
@BuildStep(onlyIf = { IsDevelopment.class, DevServicesConfig.Enabled.class })

extensions/devservices/runtime/src/main/java/io/quarkus/devservice/runtime/config/DevServicesConfigBuilder.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@ public SmallRyeConfigBuilder configBuilder(SmallRyeConfigBuilder builder) {
1313

1414
@Override
1515
public int priority() {
16-
// What's the right priority? This is a cheeky dynamic override, so a high priority seems correct, but dev services are supposed to fill in gaps in existing information.
17-
// Dev services should be looking at those sources and not doing anything if there's existing config,
18-
// so a very low priority is also arguably correct.
19-
// In principle the priority actually shouldn't matter much, but in practice it needs to not be higher than Arquillian config overrides or some tests fail
20-
2116
return 10;
2217
}
2318
}

0 commit comments

Comments
 (0)