Skip to content

Commit

Permalink
Periodic tasks will reuse any context to deliver timer events indepen…
Browse files Browse the repository at this point in the history
…dantly of the context. Unlike timers (which reuse the current context whether it is a duplicate) a periodic should not capture duplicate context as they would extend the lifecycle of the duplicated context. Instead a periodic should duplicate the current context so each timer event will have its own independant lifecycle.

Update the implementation of internal schedule tasks to unwrap the context of the scheduler timer task and then duplicate it when an timer event is emitted.
  • Loading branch information
vietj committed Dec 21, 2023
1 parent 7ca87e2 commit 74a8cc6
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 7 deletions.
8 changes: 6 additions & 2 deletions src/main/java/io/vertx/core/impl/VertxImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ public EventBus eventBus() {
@Override
public long setPeriodic(long initialDelay, long delay, Handler<Long> handler) {
ContextInternal ctx = getOrCreateContext();
return scheduleTimeout(ctx, true, initialDelay, delay, TimeUnit.MILLISECONDS, ctx.isDeployment(), handler);
return scheduleTimeout(ctx.unwrap(), true, initialDelay, delay, TimeUnit.MILLISECONDS, ctx.isDeployment(), handler);
}

public long setTimer(long delay, Handler<Long> handler) {
Expand Down Expand Up @@ -977,7 +977,11 @@ class InternalTimerHandler implements Handler<Void>, Closeable, Runnable {

@Override
public void run() {
context.emit(this);
ContextInternal dispatcher = context;
if (periodic) {
dispatcher = dispatcher.duplicate();
}
dispatcher.emit(this);
}

public void handle(Void v) {
Expand Down
28 changes: 23 additions & 5 deletions src/test/java/io/vertx/core/TimerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,30 +267,48 @@ public void testTimerOnContext() {

@Test
public void testPeriodicOnContext() {
testPeriodicOnContext(((VertxInternal)vertx).createEventLoopContext());
}

@Test
public void testPeriodicOnDuplicatedContext() {
testPeriodicOnContext(((VertxInternal)vertx).createEventLoopContext().duplicate());
}

private void testPeriodicOnContext(ContextInternal ctx2) {
disableThreadChecks();
waitFor(4);
ContextInternal ctx1 = ((VertxInternal)vertx).createEventLoopContext();
ContextInternal ctx2 = ((VertxInternal)vertx).createEventLoopContext();
assertNotSame(ctx1, ctx2);
ctx2.runOnContext(v -> {
vertx.setPeriodic(10, new Handler<Long>() {
Thread th = Thread.currentThread();
vertx.setPeriodic(10, new Handler<>() {
int count;

@Override
public void handle(Long l) {
assertSame(ctx2, vertx.getOrCreateContext());
assertSame(th, Thread.currentThread());
ContextInternal current = (ContextInternal) vertx.getOrCreateContext();
assertNotNull(current);
assertTrue(current.isDuplicate());
assertNotSame(ctx2, current);
assertSame(ctx2.unwrap(), current.unwrap());
if (++count == 2) {
vertx.cancelTimer(l);
}
complete();
}
});
ctx1.setPeriodic(10, new Handler<Long>() {
ctx1.setPeriodic(10, new Handler<>() {
int count;

@Override
public void handle(Long l) {
assertSame(ctx1, vertx.getOrCreateContext());
ContextInternal current = (ContextInternal) vertx.getOrCreateContext();
assertNotNull(current);
assertTrue(current.isDuplicate());
assertNotSame(ctx1, current);
assertSame(ctx1, current.unwrap());
if (++count == 2) {
vertx.cancelTimer(l);
}
Expand Down

0 comments on commit 74a8cc6

Please sign in to comment.