Skip to content

Commit c08b914

Browse files
committed
Use a Priority class instead of int for shutdown tasks priorities
1 parent 75b63ca commit c08b914

File tree

14 files changed

+147
-55
lines changed

14 files changed

+147
-55
lines changed

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ public final class ShutdownContextBuildItem extends SimpleBuildItem
2020
}
2121

2222
@Override
23-
public void addShutdownTask(int priority, Runnable runnable) {
24-
throw new IllegalStateException();
25-
}
26-
27-
@Override
28-
public void addLastShutdownTask(int priority, Runnable runnable) {
23+
public void addShutdownTask(Priority priority, Runnable runnable) {
2924
throw new IllegalStateException();
3025
}
3126
}

core/runtime/src/main/java/io/quarkus/runtime/ExecutorRecorder.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.quarkus.runtime;
22

3+
import static io.quarkus.runtime.ShutdownContext.*;
4+
35
import java.time.Duration;
46
import java.util.List;
57
import java.util.Optional;
@@ -39,7 +41,7 @@ public ScheduledExecutorService setupRunTime(ShutdownContext shutdownContext,
3941
LaunchMode launchMode, ThreadFactory threadFactory, ContextHandler<Object> contextHandler) {
4042
final EnhancedQueueExecutor underlying = createExecutor(threadPoolConfig, threadFactory, contextHandler);
4143
if (launchMode == LaunchMode.DEVELOPMENT) {
42-
shutdownContext.addLastShutdownTask(new Runnable() {
44+
shutdownContext.addShutdownTask(Priority.core(), new Runnable() {
4345
@Override
4446
public void run() {
4547
for (Runnable i : underlying.shutdownNow()) {
@@ -53,7 +55,7 @@ public void run() {
5355
});
5456
} else {
5557
Runnable shutdownTask = createShutdownTask(threadPoolConfig, underlying);
56-
shutdownContext.addLastShutdownTask(shutdownTask);
58+
shutdownContext.addShutdownTask(Priority.core(), shutdownTask);
5759
}
5860
if (threadPoolConfig.prefill()) {
5961
underlying.prestartAllCoreThreads();

core/runtime/src/main/java/io/quarkus/runtime/ShutdownContext.java

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import java.io.Closeable;
44
import java.io.IOException;
55

6-
import jakarta.interceptor.Interceptor;
7-
86
import org.jboss.logging.Logger;
97

108
/**
@@ -14,21 +12,118 @@
1412
*/
1513
public interface ShutdownContext {
1614

17-
int DEFAULT_PRIORITY = Interceptor.Priority.LIBRARY_AFTER;
18-
int SHUTDOWN_EVENT_PRIORITY = DEFAULT_PRIORITY + 100_000;
15+
/**
16+
* Priority that define the order in which shutdown tasks are invoked.
17+
*/
18+
interface Priority {
19+
int value();
1920

20-
default void addShutdownTask(Runnable runnable) {
21-
addShutdownTask(DEFAULT_PRIORITY, runnable);
22-
}
21+
/**
22+
* For shutdown tasks that have to be executed before the {@link ShutdownEvent application shutdown event}.
23+
*/
24+
static Priority application(int priority) {
25+
if (priority == 0) {
26+
// do not allow 0 priority as it has a "unique" meaning here.
27+
throw new IllegalArgumentException("Use the applicationShutdownEvent() instead.");
28+
}
29+
return PriorityImpl.priority(priority, PriorityImpl.APPLICATION_VALUE, Integer.MAX_VALUE);
30+
}
31+
32+
/**
33+
* This "unique" priority represents the execution of the {@link ShutdownEvent application shutdown event}.
34+
*/
35+
static Priority applicationShutdownEvent() {
36+
return PriorityImpl.APPLICATION;
37+
}
38+
39+
/**
40+
* For extension shutdown tasks that are executed after all {@link ShutdownEvent application shutdown event} handlers,
41+
* but may still require access to some CDI beans.
42+
*/
43+
static Priority extensionPreCdi(int priority) {
44+
return PriorityImpl.priority(priority, PriorityImpl.EXTENSIONS_VALUE, PriorityImpl.EXTENSIONS_CDI_VALUE);
45+
}
46+
47+
/**
48+
* This "unique" priority represents the shutdown of the CDI container, and any shutdown tasks after it won't be able to
49+
* leverage any CDI beans.
50+
*/
51+
static Priority cdiShutdown() {
52+
return PriorityImpl.EXTENSIONS_CDI;
53+
}
54+
55+
/**
56+
* For extension shutdown tasks that do not require CDI beans.
57+
*/
58+
static Priority extensionPostCdi(int priority) {
59+
return PriorityImpl.priority(priority, PriorityImpl.EXTENSIONS_VALUE, PriorityImpl.EXTENSIONS_CDI_VALUE);
60+
}
61+
62+
/**
63+
* Same as {@link #extensionPostCdi(int)} with the default priority for convenience.
64+
*/
65+
static Priority extensionPostCdi() {
66+
return PriorityImpl.EXTENSION;
67+
}
2368

24-
void addShutdownTask(int priority, Runnable runnable);
69+
/**
70+
* For core extensions like Vert.x that have to be shut down in the very end.
71+
*/
72+
static Priority core(int priority) {
73+
return PriorityImpl.priority(priority, PriorityImpl.CORE_VALUE, PriorityImpl.EXTENSIONS_VALUE);
74+
}
75+
76+
/**
77+
* Same as {@link #core(int)} with the default priority for convenience.
78+
*/
79+
static Priority core() {
80+
return PriorityImpl.CORE;
81+
}
82+
83+
/**
84+
* Most likely an unusable range of priorities to run shutdown tasks after core extensions were already shut down.
85+
*/
86+
static Priority afterCore(int priority) {
87+
return PriorityImpl.priority(priority, 0, PriorityImpl.CORE_VALUE);
88+
}
89+
90+
record PriorityImpl(int value) implements Priority {
91+
private static final int CORE_VALUE = 100_000;
92+
private static final int EXTENSIONS_VALUE = 500_000;
93+
private static final int EXTENSIONS_CDI_VALUE = 550_000;
94+
private static final int APPLICATION_VALUE = 1_000_000;
2595

26-
// these are executed after all the ones added via addShutdownTask in the reverse order from which they were added
27-
default void addLastShutdownTask(Runnable runnable) {
28-
addLastShutdownTask(DEFAULT_PRIORITY, runnable);
96+
private static final Priority CORE = new PriorityImpl(CORE_VALUE);
97+
private static final Priority EXTENSION = new PriorityImpl(EXTENSIONS_VALUE);
98+
private static final Priority EXTENSIONS_CDI = new PriorityImpl(EXTENSIONS_CDI_VALUE);
99+
private static final Priority APPLICATION = new PriorityImpl(APPLICATION_VALUE);
100+
101+
private static Priority priority(int priority, int min, int max) {
102+
int value;
103+
if (priority > 0) {
104+
value = min + priority;
105+
} else {
106+
value = max + priority;
107+
}
108+
if (value >= max || value < min) {
109+
throw new IllegalArgumentException("Priority value " + priority + " (effective: " + value
110+
+ ") is not within the allowed range for this group: [" + min + ", " + max + ")");
111+
}
112+
return new PriorityImpl(value);
113+
}
114+
}
115+
116+
}
117+
118+
default void addShutdownTask(Runnable runnable) {
119+
addShutdownTask(Priority.extensionPostCdi(), runnable);
29120
}
30121

31-
void addLastShutdownTask(int priority, Runnable runnable);
122+
/**
123+
* @param priority higher the priority -- sooner the shutdown task is going to be performed.
124+
* @param runnable the shutdown task to perform.
125+
*/
126+
void addShutdownTask(Priority priority, Runnable runnable);
32127

33128
class CloseRunnable implements Runnable {
34129

core/runtime/src/main/java/io/quarkus/runtime/StartupContext.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,17 @@ public class StartupContext implements Closeable {
2121
private final Map<String, Object> values = new HashMap<>();
2222

2323
private final PriorityBlockingQueue<ShutdownTask> shutdownTasks = new PriorityBlockingQueue<>();
24-
private final PriorityBlockingQueue<ShutdownTask> lastShutdownTasks = new PriorityBlockingQueue<>();
2524
private String[] commandLineArgs;
2625
private String currentBuildStepName;
2726

2827
public StartupContext() {
2928
ShutdownContext shutdownContext = new ShutdownContext() {
3029
@Override
31-
public void addShutdownTask(int priority, Runnable runnable) {
32-
if (runnable != null) {
33-
shutdownTasks.offer(new ShutdownTask(priority, runnable));
30+
public void addShutdownTask(Priority priority, Runnable runnable) {
31+
if (runnable != null && priority != null) {
32+
shutdownTasks.offer(new ShutdownTask(priority.value(), runnable));
3433
} else {
35-
throw new IllegalArgumentException("Extension passed an invalid shutdown handler");
36-
}
37-
}
38-
39-
@Override
40-
public void addLastShutdownTask(int priority, Runnable runnable) {
41-
if (runnable != null) {
42-
lastShutdownTasks.offer(new ShutdownTask(priority, runnable));
43-
} else {
44-
throw new IllegalArgumentException("Extension passed an invalid last shutdown handler");
34+
throw new IllegalArgumentException("Extension passed an invalid shutdown priority/handler");
4535
}
4636
}
4737
};
@@ -68,7 +58,6 @@ public Object getValue(String name) {
6858
@Override
6959
public void close() {
7060
runAllAndClear(shutdownTasks);
71-
runAllAndClear(lastShutdownTasks);
7261
values.clear();
7362
}
7463

core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static io.quarkus.runtime.ConfigConfig.BuildTimeMismatchAtRuntime;
44
import static io.quarkus.runtime.ConfigConfig.BuildTimeMismatchAtRuntime.fail;
55
import static io.quarkus.runtime.ConfigConfig.BuildTimeMismatchAtRuntime.warn;
6+
import static io.quarkus.runtime.ShutdownContext.*;
67

78
import java.util.ArrayList;
89
import java.util.List;
@@ -109,6 +110,6 @@ public void releaseConfig(ShutdownContext shutdownContext) {
109110
throw new RuntimeException(
110111
"Internal errror: shutdownContext is null. This probably happened because Quarkus failed to start properly in an earlier step, or because tests were run on a Quarkus instance that had already been shut down.");
111112
}
112-
shutdownContext.addLastShutdownTask(QuarkusConfigFactory::releaseTCCLConfig);
113+
shutdownContext.addShutdownTask(Priority.core(), QuarkusConfigFactory::releaseTCCLConfig);
113114
}
114115
}

core/runtime/src/main/java/io/quarkus/runtime/dev/io/NioThreadPoolRecorder.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.quarkus.runtime.dev.io;
22

3+
import static io.quarkus.runtime.ShutdownContext.*;
4+
35
import io.quarkus.dev.io.NioThreadPoolThreadFactory;
46
import io.quarkus.runtime.ShutdownContext;
57
import io.quarkus.runtime.annotations.Recorder;
@@ -11,7 +13,7 @@ public void updateTccl(ShutdownContext context) {
1113
ClassLoader newTccl = Thread.currentThread().getContextClassLoader();
1214
ClassLoader oldTccl = NioThreadPoolThreadFactory.updateTccl(newTccl);
1315
if (newTccl != oldTccl) {
14-
context.addLastShutdownTask(new Runnable() {
16+
context.addShutdownTask(Priority.core(), new Runnable() {
1517
@Override
1618
public void run() {
1719
NioThreadPoolThreadFactory.updateTccl(oldTccl);

extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ArcRecorder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.quarkus.runtime.LaunchMode;
2828
import io.quarkus.runtime.RuntimeValue;
2929
import io.quarkus.runtime.ShutdownContext;
30+
import io.quarkus.runtime.ShutdownContext.Priority;
3031
import io.quarkus.runtime.ShutdownEvent;
3132
import io.quarkus.runtime.StartupEvent;
3233
import io.quarkus.runtime.annotations.Recorder;
@@ -50,7 +51,7 @@ public ArcContainer initContainer(ShutdownContext shutdown, RuntimeValue<Current
5051
builder.setCurrentContextFactory(currentContextFactory != null ? currentContextFactory.getValue() : null);
5152
builder.setStrictCompatibility(strictCompatibility);
5253
ArcContainer container = Arc.initialize(builder.build());
53-
shutdown.addShutdownTask(new Runnable() {
54+
shutdown.addShutdownTask(Priority.cdiShutdown(), new Runnable() {
5455
@Override
5556
public void run() {
5657
Arc.shutdown();
@@ -113,7 +114,7 @@ public void handleLifecycleEvents(ShutdownContext context, LaunchMode launchMode
113114

114115
fireLifecycleEvent(container, new StartupEvent(), mockBeanClasses);
115116

116-
context.addShutdownTask(ShutdownContext.SHUTDOWN_EVENT_PRIORITY, new Runnable() {
117+
context.addShutdownTask(Priority.applicationShutdownEvent(), new Runnable() {
117118
@Override
118119
public void run() {
119120
fireLifecycleEvent(container, new ShutdownEvent(ApplicationLifecycleManager.shutdownReason), mockBeanClasses);

extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRecorder.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,12 @@ public DataSourceTenantConnectionResolver get() {
100100
public Supplier<JPAConfig> jpaConfigSupplier(HibernateOrmRuntimeConfig config, ShutdownContext shutdownContext) {
101101
return () -> {
102102
JPAConfig jpaConfig = new JPAConfig(config);
103-
shutdownContext.addShutdownTask(
104-
ShutdownContext.DEFAULT_PRIORITY + 1, new Runnable() {
105-
@Override
106-
public void run() {
107-
jpaConfig.shutdown();
108-
}
109-
});
103+
shutdownContext.addShutdownTask(ShutdownContext.Priority.extensionPreCdi(-1), new Runnable() {
104+
@Override
105+
public void run() {
106+
jpaConfig.shutdown();
107+
}
108+
});
110109
return jpaConfig;
111110
};
112111
}

extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.quarkus.narayana.jta.runtime;
22

3+
import static io.quarkus.runtime.ShutdownContext.*;
4+
35
import java.lang.reflect.Field;
46
import java.nio.charset.StandardCharsets;
57
import java.security.MessageDigest;
@@ -220,7 +222,7 @@ public void handleShutdown(ShutdownContext context, TransactionManagerConfigurat
220222
}
221223
}
222224
});
223-
context.addLastShutdownTask(() -> {
225+
context.addShutdownTask(Priority.core(), () -> {
224226
TransactionReaper.terminate(false);
225227
});
226228
}

extensions/observability-devservices/runtime/src/main/java/io/quarkus/observability/runtime/DevResourceShutdownRecorder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
@Recorder
88
public class DevResourceShutdownRecorder {
99
public void shutdown(ShutdownContext context) {
10-
context.addLastShutdownTask(DevResources::stop);
10+
context.addShutdownTask(ShutdownContext.Priority.core(), DevResources::stop);
1111
}
1212
}

0 commit comments

Comments
 (0)