Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
2b43f26
Bump maven-jar-plugin from 3.2.0 to 3.2.2
dependabot[bot] Apr 4, 2022
a87e032
chore: Set permissions for GitHub actions
naveensrinivasan Apr 21, 2022
c979bdd
Add httpsOnly option
U1F984 Apr 29, 2022
5807c16
FileUpload is missing in a MVC controller fix #2570
jknack May 1, 2022
a527fb1
Merge pull request #2571 from U1F984/https-only
jknack May 1, 2022
174c016
build: fix checkstyle errors
jknack May 1, 2022
39a8b11
Merge pull request #2564 from turrisxyz/setup-permissions
jknack May 1, 2022
261326f
Bump vue from 3.0.3 to 3.2.33
dependabot[bot] May 2, 2022
15a289e
netty: onComplete callback should run on caller thread. Fix #2572
jknack May 2, 2022
405d421
dependencies: jetty upgrade
jknack May 2, 2022
051ff59
Merge pull request #2573 from jooby-project/dependabot/maven/org.webj…
jknack May 2, 2022
ffeb642
Merge pull request #2556 from jooby-project/dependabot/maven/org.apac…
jknack May 2, 2022
63f3a2e
@Transactional annotation must be supported at class/type level too f…
jknack May 2, 2022
6c709ff
jooby-cli: doesn't add src/main/resources while generating maven proj…
jknack May 2, 2022
ef62ad5
v2.14.1
jknack May 2, 2022
5af6008
prepare for next development cycle
jknack May 2, 2022
af27bcb
Bump netty.version from 4.1.76.Final to 4.1.77.Final
dependabot[bot] May 9, 2022
9ee3c34
Bump lettuce-core from 6.1.6.RELEASE to 6.1.8.RELEASE
dependabot[bot] May 9, 2022
b6707bc
Bump mockito.version from 4.4.0 to 4.5.1
dependabot[bot] May 9, 2022
4874486
Merge pull request #2581 from jooby-project/dependabot/maven/mockito.…
jknack May 9, 2022
aacf570
Merge pull request #2580 from jooby-project/dependabot/maven/io.lettu…
jknack May 9, 2022
7305488
Merge pull request #2579 from jooby-project/dependabot/maven/netty.ve…
jknack May 9, 2022
f1da6d9
Add a queue for hotreload to group changes
agentgt May 9, 2022
89cc4af
Fix unit test for new jooby run for wait time
agentgt May 9, 2022
d0b1a4a
Make sonatype-lift happy
agentgt May 9, 2022
b408005
Merge pull request #2583 from agentgt/issues/2577_hotreload
jknack May 10, 2022
42b24b1
jooby-run: Add waitTimeBeforeRestart to gradle plugin
jknack May 10, 2022
cf93070
jooby-run: document waitTimeBeforeRestart. See #2577
jknack May 11, 2022
c0d82e4
build: add gradle compile to pipeline
jknack May 11, 2022
2fddb0c
build: revert gradle integration from build
jknack May 11, 2022
1143bd6
WebSocket: Fix raise condition while sending a message on connect
jknack May 14, 2022
14de379
version bump: upgrade dependencies
jknack May 14, 2022
ef55836
v2.14.2
jknack May 15, 2022
2634521
prepare for next development cycle
jknack May 15, 2022
b6b606c
build: run on 17 and latest
jknack May 15, 2022
ef7ec3f
build: revert build on jdk 17
jknack May 15, 2022
bbbb14e
Bump rest-assured from 4.3.3 to 5.0.1
dependabot[bot] May 16, 2022
012185d
Bump logback-classic from 1.2.9 to 1.2.11
dependabot[bot] May 16, 2022
0b857e9
Bump directory-watcher from 0.15.0 to 0.15.1
dependabot[bot] May 16, 2022
1e8f8b5
kotlin: upgrade to 1.6.x fix #2592
jknack May 18, 2022
48ea1b2
Merge pull request #2588 from jooby-project/dependabot/maven/io.rest-…
jknack May 18, 2022
7ddc8df
Merge pull request #2591 from jooby-project/dependabot/maven/io.methv…
jknack May 18, 2022
a8bebc2
Merge pull request #2590 from jooby-project/dependabot/maven/ch.qos.l…
jknack May 18, 2022
7335467
build(deps): bump slf4j.version from 1.7.32 to 1.7.36
dependabot[bot] May 18, 2022
d489ac8
mvc: don't generate send call on void controller method
jknack May 19, 2022
18758a4
type analyzer: detects completablefuture from kotlin
jknack May 20, 2022
9367813
build: fix random failure caused by GC?
jknack May 20, 2022
f25d3ae
build: upgrade gradle + use java 17/18
jknack May 20, 2022
fe6dcc7
Merge pull request #2593 from jooby-project/dependabot/maven/slf4j.ve…
jknack May 20, 2022
49ed759
build: fix random failure caused by raise condition
jknack May 20, 2022
2e6243b
v2.15.0
jknack May 22, 2022
e597315
prepare for next development cycle
jknack May 22, 2022
af980f5
Application startup resulted in exception: Caused by: java.lang.Class…
jknack May 27, 2022
1484ff7
dependencies: version bump
jknack May 27, 2022
eb3bfac
v2.15.1
jknack May 28, 2022
6d0d333
prepare for next development cycle
jknack May 28, 2022
32cda3f
[openapi] Duplicated endpoints for the mounted applications fix #2594
jknack May 28, 2022
e22d03d
Fix typo ("NO_CONENT" => "NO_CONTENT")
lukasbarti Jun 12, 2022
e10afbb
Merge pull request #2605 from lukasbarti/patch-1
jknack Jul 4, 2022
88df159
build(deps): bump aws-java-sdk-s3 in /modules/jooby-bom
dependabot[bot] Jul 15, 2022
94e1e39
App should return 400 code if file form field is missing
extbe Jul 21, 2022
4921171
Merge pull request #2612 from extbe/fix/issue-2611
jknack Jul 25, 2022
9481d17
Add FUNDING/sponsor file
jknack Jul 29, 2022
23e1541
Fix httpsOnly config file example
jryan128 Aug 4, 2022
1400b68
build(deps): bump undertow-core in /modules/jooby-bom
dependabot[bot] Aug 18, 2022
e97cd38
build(deps): bump undertow-core from 2.2.17.Final to 2.2.19.Final
dependabot[bot] Aug 18, 2022
11c6097
build(deps): bump jsoup from 1.14.2 to 1.15.3 in /docs
dependabot[bot] Sep 1, 2022
e7b6212
build(deps-dev): bump jsoup in /modules/jooby-whoops
dependabot[bot] Sep 1, 2022
d62c04c
cli: move configuration files to `.config/jooby.conf` fixes #2599
jknack Sep 5, 2022
47801e1
Merge pull request #2615 from jryan128/jryan128-patch-1
jknack Sep 5, 2022
d4dc0d5
Merge pull request #2618 from jooby-project/dependabot/maven/io.under…
jknack Sep 5, 2022
fe7e1f1
Merge pull request #2621 from jooby-project/dependabot/maven/modules/…
jknack Sep 5, 2022
120aee8
Merge pull request #2617 from jooby-project/dependabot/maven/modules/…
jknack Sep 5, 2022
c60da54
Merge pull request #2610 from jooby-project/dependabot/maven/modules/…
jknack Sep 5, 2022
cc4cdc1
Merge pull request #2620 from jooby-project/dependabot/maven/docs/org…
jknack Sep 5, 2022
aac8aaf
version bump: upgrade major dependencies
jknack Sep 6, 2022
de306b3
doc: Number of worker threads fixes #2616
jknack Sep 6, 2022
9ae88d4
ServerOptions#setHost missing a 0? fixes #2614
jknack Sep 6, 2022
9640984
encoder: should consider route produce types, fixes #2613
jknack Sep 6, 2022
2ed1342
v2.16.0
jknack Sep 6, 2022
157a1c1
prepare for next development cycle
jknack Sep 6, 2022
9329462
Regression: Bug: Fix NullPointerException, will fixing content negota…
jknack Sep 6, 2022
4d7be54
v2.16.1
jknack Sep 6, 2022
0f5e57a
prepare for next development cycle
jknack Sep 6, 2022
a420491
version: upgrade jooby dependencies
jknack Oct 24, 2022
82c4281
Preflight requests fail with 415 when MVC Controller method has @Cons…
jknack Oct 24, 2022
0a4b38a
version: updates bom file
jknack Oct 29, 2022
ad803e8
dependencies: upgrade dependencies
jknack Oct 30, 2022
0ad1485
Added jax-rs path-param
dmitryb-dev Nov 2, 2022
1d36d73
Merge pull request #2667 from dmitryb-dev/add-jax-rs-path-param
jknack Nov 3, 2022
a5558d5
version bump
jknack Nov 26, 2022
89ea421
Merge pull request #2673 from jooby-project/versionbump
jknack Nov 27, 2022
e1e122d
Reproducible byte for byte jars fix #2670
jknack Nov 27, 2022
30cd4e5
version bump: upgrade h2
jknack Nov 27, 2022
7088fd3
build+deps: get back build upgrade servers dependencies
jknack Dec 7, 2022
a7537a7
AccessLogger logs miss protocol and content length when using Kotlin …
jknack Dec 26, 2022
36cde51
version bump: upgrade major dependencies
jknack Mar 1, 2023
7d85f96
encoder: should consider all produce types before default TO_STRING
froque Mar 2, 2023
d61c655
Merge pull request #2805 from froque/2804_fix_regression_encoders_mul…
jknack Mar 2, 2023
25c4fdb
revert: Regression with encoder: should consider route produce types …
jknack Mar 4, 2023
81dcd67
build: rename test with wrong name
jknack Mar 4, 2023
7161820
build: remove System.out calls
jknack Mar 4, 2023
7a53ee1
2.15][Netty] Cannot access encoder in case of "413 Content Too Large"…
jknack Mar 4, 2023
fc8d753
Support for binary messages in WebSocket API fix #2497
jknack Feb 28, 2023
0006ced
Support for Websocket Heartbeat fix #2784
jknack Feb 28, 2023
57a8127
OpenApi jooby-maven-plugin incorrect generation in multi module maven…
jknack Feb 28, 2023
2fa18dd
v2.16.2
jknack Mar 4, 2023
5b01669
prepare for next development cycle
jknack Mar 4, 2023
3635d35
Bump ASM from 9.3 to 9.6 to enable support for Java 21
froque Oct 24, 2023
dee824b
Merge pull request #3196 from froque/upgrade_asm
jknack Oct 26, 2023
f7f289d
version bump:
jknack Oct 28, 2023
a44644f
v2.16.3
jknack Oct 28, 2023
69438ee
#3441 Bump Guice to 6.0.0
imeszaros Jun 4, 2024
e4f7b7d
Merge pull request #3442 from imeszaros/bump-guice
jknack Jun 4, 2024
d4fa18b
jetty: remove conscrypt dependency
jknack Jun 5, 2024
149998c
set version to 2.16.4
jknack Jun 5, 2024
b404283
version bump: upgrade servers
jknack Jun 5, 2024
08c9169
v2.16.4
jknack Jun 5, 2024
847e892
build: fix jetty ssl + gradle setup
jknack Jun 5, 2024
6965c8b
v2.16.4
jknack Jun 5, 2024
18a2a77
gradle-8.8
jknack Jun 6, 2024
1ab0210
prepare for next development cycle
jknack Jun 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public class RunMojo extends BaseMojo {
@Parameter(property = "jooby.port")
private Integer port;

/**
* How long to wait after last file change to restart. Default is: <code>500</code> milliseconds.
*/
@Parameter(property = "jooby.waitTimeBeforeRestart")
private Long waitTimeBeforeRestart;

@Override protected void doExecute(List<MavenProject> projects, String mainClass)
throws Throwable {
Maven maven = getMaven();
Expand Down Expand Up @@ -122,6 +128,7 @@ private JoobyRunOptions createOptions(String mainClass) {
options.setCompileExtensions(compileExtensions);
}
options.setPort(port);
options.setWaitTimeBeforeRestart(waitTimeBeforeRestart);
options.setProjectName(session.getCurrentProject().getArtifactId());
if (restartExtensions != null) {
options.setRestartExtensions(restartExtensions);
Expand Down
142 changes: 132 additions & 10 deletions modules/jooby-run/src/main/java/io/jooby/run/JoobyRun.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Clock;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;

/**
Expand Down Expand Up @@ -57,6 +63,13 @@ private static class AppModule {
private Module module;
private ClassLoader contextClassLoader;
private int counter;
private final AtomicInteger state = new AtomicInteger(CLOSED);
private static final int CLOSED = 1 << 0;
private static final int UNLOADING = 1 << 1;
private static final int UNLOADED = 1 << 2;
private static final int STARTING = 1 << 3;
private static final int RESTART = 1 << 4;
private static final int RUNNING = 1 << 5;

AppModule(Logger logger, ExtModuleLoader loader, ClassLoader contextClassLoader,
JoobyRunOptions conf) {
Expand All @@ -67,6 +80,11 @@ private static class AppModule {
}

public Exception start() {
if (!(state.compareAndSet(CLOSED, STARTING)
|| state.compareAndSet(UNLOADED, STARTING))) {
debugState("Jooby already starting.");
return null;
}
try {
module = loader.loadModule(conf.getProjectName());
ModuleClassLoader classLoader = module.getClassLoader();
Expand Down Expand Up @@ -102,6 +120,9 @@ public Exception start() {
} catch (Throwable x) {
printErr(x);
} finally {
if (state.compareAndSet(STARTING, RUNNING)) {
debugState("Jooby is now");
}
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
// In theory: application started successfully, then something went wrong. Still, users
Expand Down Expand Up @@ -139,10 +160,19 @@ private boolean isFatal(Throwable cause) {
|| cause instanceof VirtualMachineError;
}

public boolean isStarting() {
long s = state.longValue();
return s > CLOSED && s < RUNNING;
}

public void restart() {
closeServer();
unloadModule();
start();
if (state.compareAndSet(RUNNING, RESTART)) {
closeServer();
unloadModule();
start();
} else {
debugState("Already restarting.");
}
}

public void close() {
Expand All @@ -160,27 +190,65 @@ private Throwable withoutReflection(Throwable cause) {
}

private void unloadModule() {
if (!state.compareAndSet(CLOSED, UNLOADING)) {
debugState("Cannot unload as server isn't closed.");
return;
}
try {
if (module != null) {
loader.unload(conf.getProjectName(), module);
}
} catch (Exception x) {
logger.debug("unload module resulted in exception", x);
} finally {
state.compareAndSet(UNLOADING, UNLOADED);
module = null;
}
}

private void closeServer() {
try {
Class ref = module.getClassLoader().loadClass(SERVER_REF);
debugState("Closing server.");
Class<?> ref = module.getClassLoader().loadClass(SERVER_REF);
ref.getDeclaredMethod(SERVER_REF_STOP).invoke(null);
} catch (Exception x) {
logger.error("Application shutdown resulted in exception", withoutReflection(x));
} finally {
state.set(CLOSED);
}
}

private void debugState(String message) {
if (logger.isDebugEnabled()) {
String name;
switch (state.get()) {
case CLOSED:
name = "CLOSED";
break;
case UNLOADING:
name = "UNLOADING";
break;
case UNLOADED:
name = "UNLOADED";
break;
case STARTING:
name = "STARTING";
break;
case RESTART:
name = "RESTART";
break;
case RUNNING:
name = "RUNNING";
break;
default:
throw new IllegalStateException("BUG");
}
logger.debug(message + " state: {}", name);
}
}
}


static final String SERVER_REF = "io.jooby.run.ServerRef";

static final String SERVER_REF_STOP = "stop";
Expand All @@ -199,13 +267,28 @@ private void closeServer() {

private AppModule module;

private final Clock clock;

private final ConcurrentLinkedQueue<Event> queue = new ConcurrentLinkedQueue<>();

/*
* How long we wait after the last change before restart
*/
private final long waitTimeBeforeRestartMillis;

private final long initialDelayBeforeFirstRestartMillis;

/**
* Creates a new instances with the given options.
*
* @param options Run options.
*/
public JoobyRun(JoobyRunOptions options) {
this.options = options;
clock = Clock.systemUTC(); // Possibly change for unit test
waitTimeBeforeRestartMillis = options.getWaitTimeBeforeRestart();
// this might not need to be configurable
initialDelayBeforeFirstRestartMillis = JoobyRunOptions.INITIAL_DELAY_BEFORE_FIRST_RESTART;
}

/**
Expand Down Expand Up @@ -250,20 +333,30 @@ public boolean addResource(Path path) {
*
* @throws Throwable If something goes wrong.
*/
@SuppressWarnings("FutureReturnValueIgnored")
public void start() throws Throwable {
this.watcher = newWatcher();
try {

logger.debug("project: {}", toString());

ModuleFinder[] finders = {
new FlattenClasspath(options.getProjectName(), resources, dependencies)};
ModuleFinder[] finders =
{new FlattenClasspath(options.getProjectName(), resources, dependencies)};

ExtModuleLoader loader = new ExtModuleLoader(finders);
module = new AppModule(logger, loader, Thread.currentThread().getContextClassLoader(),
options);
module =
new AppModule(logger, loader, Thread.currentThread().getContextClassLoader(), options);
ScheduledExecutorService se;
Exception error = module.start();
if (error == null) {
watcher.watch();
se = Executors.newScheduledThreadPool(1);
se.scheduleAtFixedRate(this::actualRestart, initialDelayBeforeFirstRestartMillis,
waitTimeBeforeRestartMillis, TimeUnit.MILLISECONDS);
try {
watcher.watch();
} finally {
se.shutdownNow();
}
} else {
// exit
shutdown();
Expand All @@ -278,7 +371,36 @@ public void start() throws Throwable {
* Restart the application.
*/
public void restart() {
module.restart();
//module.restart();
queue.offer(new Event(clock.millis()));
}

private static class Event {
private final long time;
Event(long time) {
this.time = time;
}
};



private synchronized void actualRestart() {
if (module.isStarting()) {
return; // We don't empty the queue. This is the case a change was made while starting.
}
// Event e = queue.peek();
long t = clock.millis();
Event e = queue.peek();
if (e == null) {
return; // queue was empty
}
for (; e != null && (t - e.time) > waitTimeBeforeRestartMillis; e = queue.peek()) {
queue.poll();
}
// e will be null if the queue is empty which means all events were old enough
if (e == null) {
module.restart();
}
}

/**
Expand Down
26 changes: 26 additions & 0 deletions modules/jooby-run/src/main/java/io/jooby/run/JoobyRunOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public class JoobyRunOptions {

private Integer port = null;

private Long waitTimeBeforeRestart = DEFAULT_WAIT_TIME_BEFORE_RESTART;

private static final long DEFAULT_WAIT_TIME_BEFORE_RESTART = 500L;

static final long INITIAL_DELAY_BEFORE_FIRST_RESTART = 5000L;

/**
* Project name.
*
Expand Down Expand Up @@ -82,6 +88,26 @@ public void setPort(Integer port) {
this.port = port;
}

/**
* How long to wait after last file change to restart. Default is: <code>500</code> milliseconds.
*
* @return Wait time in milliseconds.
*/
public Long getWaitTimeBeforeRestart() {
return waitTimeBeforeRestart;
}

/**
* Set wait time before restart on file change.
*
* @param waitTimeBeforeRestart the time in milliseconds.
*/
public void setWaitTimeBeforeRestart(Long waitTimeBeforeRestart) {
if (waitTimeBeforeRestart != null) {
this.waitTimeBeforeRestart = waitTimeBeforeRestart;
}
}

/**
* List of file extensions that trigger an application restart. Default is: <code>conf</code>,
* <code>properties</code> and <code>class</code>.
Expand Down