Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheduler: document @Scheduled#executionMaxDelay() #43563

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 23 additions & 4 deletions docs/src/main/asciidoc/scheduler-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@
void myMethod() { }
----

=== Delayed Execution
[[delayed_start]]
=== Delayed Start of a Trigger

`@Scheduled` provides two ways to delay the time a trigger should start firing at.

Expand Down Expand Up @@ -249,9 +250,8 @@
NOTE: If `@Scheduled#delay()` is set to a value greater than zero the value of `@Scheduled#delayed()` is ignored.

The main advantage over `@Scheduled#delay()` is that the value is configurable.
The `delay` attribute supports <<config-reference#property-expressions,Property Expressions>> including default values and nested
Property Expressions. (Note that `"{property.path}"` style expressions are still supported but don't offer the full functionality of Property Expressions.)

The `delay` attribute supports <<config-reference#property-expressions,Property Expressions>> including default values and nested Property Expressions.
(Note that `"{property.path}"` style expressions are still supported but don't offer the full functionality of Property Expressions.)

[source,java]
----
Expand All @@ -260,8 +260,27 @@
----
<1> The config property `myMethod.delay.expr` is used to set the delay.

[[delayed_execution]]
=== Delayed Execution

`@Scheduled#executionMaxDelay()` can be set to delay each execution of a scheduled method.
The value represents the maximum delay between the activation of the trigger and the execution of the scheduled method.
The actual delay is a randomized number between 0 and the maximum specified delay.

The value is parsed with `DurationConverter#parseDuration(String)`.
It can be a property expression, in which case, the scheduler attempts to use the configured value instead: `@Scheduled(executionMaxDelay = "${myJob.maxDelay}")`.

Check warning on line 271 in docs/src/main/asciidoc/scheduler-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using ', which (non restrictive clause preceded by a comma)' or 'that (restrictive clause without a comma)' rather than 'which'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using ', which (non restrictive clause preceded by a comma)' or 'that (restrictive clause without a comma)' rather than 'which'.", "location": {"path": "docs/src/main/asciidoc/scheduler-reference.adoc", "range": {"start": {"line": 271, "column": 36}}}, "severity": "INFO"}
Additionally, the property expression can specify a default value:
`@Scheduled(executionMaxDelay = "${myJob.maxDelay}:500ms}")`.

[source,java]
----
@Scheduled(every = "2s", executionMaxDelay = "500ms") <1>
void everyTwoSeconds() { }
----
<1> The delay will be a value between 0 and 500 milliseconds. As a result, the period between to `everyTwoSeconds()` executions will be roughly between one and a half and two and a half seconds.

[[concurrent_execution]]
=== Concurrent Execution

Check warning on line 283 in docs/src/main/asciidoc/scheduler-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Headings] Use sentence-style capitalization in '1.7. Concurrent Execution'. Raw Output: {"message": "[Quarkus.Headings] Use sentence-style capitalization in '1.7. Concurrent Execution'.", "location": {"path": "docs/src/main/asciidoc/scheduler-reference.adoc", "range": {"start": {"line": 283, "column": 1}}}, "severity": "INFO"}

Check warning on line 283 in docs/src/main/asciidoc/scheduler-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.HeadingPunctuation] Do not use end punctuation in headings. Raw Output: {"message": "[Quarkus.HeadingPunctuation] Do not use end punctuation in headings.", "location": {"path": "docs/src/main/asciidoc/scheduler-reference.adoc", "range": {"start": {"line": 283, "column": 1}}}, "severity": "INFO"}

By default, a scheduled method can be executed concurrently.
Nevertheless, it is possible to specify the strategy to handle concurrent executions via `@Scheduled#concurrentExecution()`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.quarkus.scheduler.test.delayedexecution;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.concurrent.CountDownLatch;
Expand All @@ -11,8 +10,10 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.runtime.StartupEvent;
import io.quarkus.scheduler.DelayedExecution;
import io.quarkus.scheduler.Scheduled;
import io.quarkus.scheduler.Scheduler;
import io.quarkus.test.QuarkusUnitTest;

public class DelayedExecutionTest {
Expand All @@ -24,23 +25,38 @@ public class DelayedExecutionTest {
@Test
public void testSimpleScheduledJobs() throws InterruptedException {
assertTrue(Jobs.EVENT_LATCH.await(5, TimeUnit.SECONDS));
assertTrue(Jobs.LATCH.await(5, TimeUnit.SECONDS));
assertTrue(Jobs.LATCH1.await(5, TimeUnit.SECONDS));
assertTrue(Jobs.LATCH2.await(5, TimeUnit.SECONDS));
}

static class Jobs {

static final CountDownLatch LATCH = new CountDownLatch(1);
static final CountDownLatch EVENT_LATCH = new CountDownLatch(1);
static final CountDownLatch LATCH1 = new CountDownLatch(1);
static final CountDownLatch LATCH2 = new CountDownLatch(1);
static final CountDownLatch EVENT_LATCH = new CountDownLatch(2);

@Scheduled(identity = "foo", every = "1s", executionMaxDelay = "500ms")
static void everySecond() {
LATCH.countDown();
LATCH1.countDown();
}

void start(@Observes StartupEvent event, Scheduler scheduler) {
scheduler.newJob("bar")
.setInterval("1s")
.setExecutionMaxDelay("500ms")
.setTask(se -> {
LATCH2.countDown();
}).schedule();
}

void onDelay(@Observes DelayedExecution delayedExecution) {
assertTrue(delayedExecution.getDelay() < 500);
assertEquals("foo", delayedExecution.getExecution().getTrigger().getId());
EVENT_LATCH.countDown();
String id = delayedExecution.getExecution().getTrigger().getId();
if ("foo".equals(id) || "bar".equals(id)) {
EVENT_LATCH.countDown();
} else {
throw new IllegalStateException("Invalid job identity: " + id);
}
}

}
Expand Down