Skip to content

Commit 7732212

Browse files
committed
Callback when the server has started fix #575
1 parent 2dc458d commit 7732212

File tree

7 files changed

+128
-4
lines changed

7 files changed

+128
-4
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.jooby.issues;
2+
3+
import org.jooby.test.ServerFeature;
4+
import org.junit.Test;
5+
6+
import java.util.concurrent.atomic.AtomicInteger;
7+
8+
public class Issue575 extends ServerFeature {
9+
10+
{
11+
AtomicInteger inc = new AtomicInteger();
12+
onStarted(r -> {
13+
inc.incrementAndGet();
14+
});
15+
16+
onStarted(() -> {
17+
inc.incrementAndGet();
18+
});
19+
20+
use((env, conf, binder) -> {
21+
env.onStarted(r -> inc.incrementAndGet());
22+
env.onStarted(() -> inc.incrementAndGet());
23+
});
24+
25+
get("/575", () -> inc.get());
26+
}
27+
28+
@Test
29+
public void onStartedCallback() throws Exception {
30+
request()
31+
.get("/575")
32+
.expect("4");
33+
}
34+
}

jooby/src/main/java/org/jooby/Env.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
import javaslang.API;
4747
import javaslang.control.Option;
48+
import javaslang.control.Try;
4849
import javaslang.control.Try.CheckedConsumer;
4950

5051
/**
@@ -265,6 +266,8 @@ default Env build(final Config config) {
265266

266267
private ImmutableList.Builder<CheckedConsumer<Registry>> start = ImmutableList.builder();
267268

269+
private ImmutableList.Builder<CheckedConsumer<Registry>> started = ImmutableList.builder();
270+
268271
private ImmutableList.Builder<CheckedConsumer<Registry>> shutdown = ImmutableList.builder();
269272

270273
private Map<String, Function<String, String>> xss = new HashMap<>();
@@ -321,11 +324,22 @@ public Env onStart(final CheckedConsumer<Registry> task) {
321324
return this;
322325
}
323326

327+
@Override
328+
public LifeCycle onStarted(CheckedConsumer<Registry> task) {
329+
this.started.add(task);
330+
return this;
331+
}
332+
324333
@Override
325334
public List<CheckedConsumer<Registry>> startTasks() {
326335
return this.start.build();
327336
}
328337

338+
@Override
339+
public List<CheckedConsumer<Registry>> startedTasks() {
340+
return this.started.build();
341+
}
342+
329343
@Override
330344
public Map<String, Function<String, String>> xss() {
331345
return Collections.unmodifiableMap(xss);
@@ -518,6 +532,11 @@ default Function<String, String> xss(final String... xss) {
518532
*/
519533
List<CheckedConsumer<Registry>> startTasks();
520534

535+
/**
536+
* @return List of start tasks.
537+
*/
538+
List<CheckedConsumer<Registry>> startedTasks();
539+
521540
/**
522541
* @return List of stop tasks.
523542
*/

jooby/src/main/java/org/jooby/Jooby.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ public EnvDep(final Predicate<String> predicate, final Consumer<Config> callback
657657

658658
/** startup callback . */
659659
private transient List<CheckedConsumer<Registry>> onStart = new ArrayList<>();
660+
private transient List<CheckedConsumer<Registry>> onStarted = new ArrayList<>();
660661

661662
/** stop callback . */
662663
private transient List<CheckedConsumer<Registry>> onStop = new ArrayList<>();
@@ -771,6 +772,7 @@ private Jooby use(final Optional<String> path, final Jooby app) {
771772
});
772773
// start/stop callback
773774
app.onStart.forEach(this.onStart::add);
775+
app.onStarted.forEach(this.onStarted::add);
774776
app.onStop.forEach(this.onStop::add);
775777
// mapper
776778
if (app.mapper != null) {
@@ -799,8 +801,8 @@ public Jooby env(final Env.Builder env) {
799801

800802
@Override
801803
public Jooby onStart(final CheckedRunnable callback) {
802-
requireNonNull(callback, "Callback is required.");
803-
return onStart(a -> callback.run());
804+
LifeCycle.super.onStart(callback);
805+
return this;
804806
}
805807

806808
@Override
@@ -811,9 +813,22 @@ public Jooby onStart(final CheckedConsumer<Registry> callback) {
811813
}
812814

813815
@Override
814-
public Jooby onStop(final CheckedRunnable callback) {
816+
public Jooby onStarted(final CheckedRunnable callback) {
817+
LifeCycle.super.onStarted(callback);
818+
return this;
819+
}
820+
821+
@Override
822+
public Jooby onStarted(final CheckedConsumer<Registry> callback) {
815823
requireNonNull(callback, "Callback is required.");
816-
return onStop(e -> callback.run());
824+
onStarted.add(callback);
825+
return this;
826+
}
827+
828+
@Override
829+
public Jooby onStop(final CheckedRunnable callback) {
830+
LifeCycle.super.onStop(callback);
831+
return this;
817832
}
818833

819834
@Override
@@ -1978,6 +1993,11 @@ private void start(final String[] args, final Consumer<List<Route.Definition>> r
19781993
end - start,
19791994
printer);
19801995

1996+
// started services
1997+
for (CheckedConsumer<Registry> onStarted : this.onStarted) {
1998+
onStarted.accept(this);
1999+
}
2000+
19812001
boolean join = conf.hasPath("server.join") ? conf.getBoolean("server.join") : true;
19822002
if (join) {
19832003
server.join();
@@ -2695,6 +2715,7 @@ private Injector bootstrap(final Config args,
26952715
});
26962716

26972717
onStart.addAll(0, finalEnv.startTasks());
2718+
onStarted.addAll(0, finalEnv.startedTasks());
26982719
onStop.addAll(finalEnv.stopTasks());
26992720

27002721
// clear bag and freeze it

jooby/src/main/java/org/jooby/LifeCycle.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,20 @@ default LifeCycle lifeCycle(final Class<?> service) {
260260
*/
261261
LifeCycle onStart(CheckedConsumer<Registry> task);
262262

263+
/**
264+
* Add a started lifecycle event. Started callbacks are executed when the application is ready:
265+
* modules and servers has been started.
266+
*
267+
* You should ONLY call this method while the application is been initialized or while
268+
* {@link Jooby.Module#configure(Env, Config, com.google.inject.Binder)}.
269+
*
270+
* The behavior of this method once application has been initialized is <code>undefined</code>.
271+
*
272+
* @param task Task to run.
273+
* @return This env.
274+
*/
275+
LifeCycle onStarted(CheckedConsumer<Registry> task);
276+
263277
/**
264278
* Add a start lifecycle event, useful for initialize and/or start services at startup time.
265279
*
@@ -275,6 +289,22 @@ default LifeCycle onStart(final CheckedRunnable task) {
275289
return onStart(app -> task.run());
276290
}
277291

292+
/**
293+
* Add a started lifecycle event. Started callbacks are executed when the application is ready:
294+
* modules and servers has been started.
295+
*
296+
* You should ONLY call this method while the application is been initialized or while
297+
* {@link Jooby.Module#configure(Env, Config, com.google.inject.Binder)}.
298+
*
299+
* The behavior of this method once application has been initialized is <code>undefined</code>.
300+
*
301+
* @param task Task to run.
302+
* @return This env.
303+
*/
304+
default LifeCycle onStarted(final CheckedRunnable task) {
305+
return onStarted(app -> task.run());
306+
}
307+
278308
/**
279309
* Add a stop lifecycle event, useful for cleanup and/or stop service at stop time.
280310
*

jooby/src/test/java/org/jooby/EnvTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.Optional;
1212
import java.util.function.Function;
1313

14+
import javaslang.control.Try;
1415
import org.junit.Test;
1516

1617
import com.google.common.collect.ImmutableMap;
@@ -122,6 +123,9 @@ public LifeCycle onStart(final CheckedConsumer<Registry> task) {
122123
return null;
123124
}
124125

126+
@Override
127+
public LifeCycle onStarted(CheckedConsumer<Registry> task) { return null; }
128+
125129
@Override
126130
public LifeCycle onStop(final CheckedConsumer<Registry> task) {
127131
return null;
@@ -162,6 +166,9 @@ public List<CheckedConsumer<Registry>> startTasks() {
162166
return null;
163167
}
164168

169+
@Override
170+
public List<CheckedConsumer<Registry>> startedTasks() { return null; }
171+
165172
@Override
166173
public List<CheckedConsumer<Registry>> stopTasks() {
167174
return null;

jooby/src/test/java/org/jooby/JoobyTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ public void customEnv() throws Exception {
838838
Env env = unit.mock(Env.class);
839839
expect(env.name()).andReturn("dev").times(2);
840840
expect(env.startTasks()).andReturn(Collections.emptyList());
841+
expect(env.startedTasks()).andReturn(Collections.emptyList());
841842
expect(env.stopTasks()).andReturn(Collections.emptyList());
842843

843844
Env.Builder builder = unit.get(Env.Builder.class);

md/app.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ Start/stop callbacks are accessible via application:
3636
onStart(() -> {
3737
log.info("starting app");
3838
});
39+
3940
onStop(() -> {
4041
log.info("stopping app");
4142
});
43+
44+
onStarted(() -> {
45+
log.info("app started");
46+
});
4247
}
4348
```
4449

@@ -52,14 +57,21 @@ public class MyModule implements Jooby.Module {
5257
env.onStart(() -> {
5358
log.info("starting module");
5459
});
60+
5561
env.onStop(() -> {
5662
log.info("stopping module");
5763
});
64+
65+
env.onStarted(() -> {
66+
log.info("app started");
67+
});
5868
}
5969

6070
}
6171
```
6272

73+
The `onStart` callbacks are part of bootstrap and executed before server is ready. The `onStarted` callbacks are executed when server is ready.
74+
6375
Modules are covered later all you need to know now is that you can start/stop module as you usually do from your application.
6476

6577
### order

0 commit comments

Comments
 (0)