Skip to content

Commit 491f4e1

Browse files
committed
add execution timeout cooperation
1 parent e19bdd5 commit 491f4e1

File tree

4 files changed

+154
-17
lines changed

4 files changed

+154
-17
lines changed

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/pages/docs/services/batch.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Here are some common use cases:
1717

1818
```java
1919
@Batch
20-
public Map<String, Boolean> batchInsertUsers(Map<String, User> users) {
20+
public Map<String, Boolean> insertUsers(Map<String, User> users) {
2121
Set<String> results = database.batchInsert(users.values());
2222
return users.entrySet().stream()
2323
.collect(Collectors.toMap(
@@ -29,7 +29,7 @@ Here are some common use cases:
2929

3030
```kotlin
3131
@Batch
32-
fun batchInsertUsers(users: Map<String, User>): Map<String, Boolean> {
32+
fun insertUsers(users: Map<String, User>): Map<String, Boolean> {
3333
val results = database.batchInsert(users.values)
3434
return users.mapValues { (_, user) -> results.contains(user.id) }
3535
}
@@ -45,7 +45,7 @@ Here are some common use cases:
4545

4646
```java
4747
@Batch
48-
public Map<String, Boolean> sendBatchEmails(Map<String, EmailRequest> emails) {
48+
public Map<String, Boolean> sendEmails(Map<String, EmailRequest> emails) {
4949
Set<String> results = emailService.sendbatch(emails.values());
5050
return emails.entrySet().stream()
5151
.collect(Collectors.toMap(
@@ -57,7 +57,7 @@ Here are some common use cases:
5757

5858
```kotlin
5959
@Batch
60-
fun sendBatchEmails(emails: Map<String, EmailRequest>): Map<String, Boolean> {
60+
fun sendEmails(emails: Map<String, EmailRequest>): Map<String, Boolean> {
6161
val results = emailService.sendbatch(emails.values)
6262
return emails.mapValues { (_, email) -> results.contains(email.id) }
6363
}

src/pages/docs/services/context.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The `io.infinitic.tasks.Task` class provides the following static properties:
1818
| [`meta`](#meta) | Map\<String, ByteArray\> | Metadata provided when dispatching the task |
1919
| [`retryIndex` ](#retry-index) | Integer | Number of times the task was automatically retried |
2020
| [`retrySequence`](#retry-sequence) | Integer | Number of times the task was manually retried |
21-
| [`attempts`](#attempts) | List<AttemptException> | list of previous `AttemptException` |
21+
| [`lastError`](#last-error) | TaskFailure? | The last error that occurred during the task execution |
2222
| `batchKey` | String? | If any, the [batch key](/docs/services/batched#optional-batch-key) provided when the task was dispatched |
2323
| `client` | InfiniticClient | An [InfiniticClient](/docs/components/terminology#clients) that can be used inside the task |
2424

src/pages/docs/services/implementation.md

Lines changed: 143 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,12 @@ There are multiple ways to define a retry policy for a Service:
154154

155155
- During the [configuration](/docs/components/workers#service-executor) of the Service Executor.
156156
- Within the implementation code of the Service itself:
157-
- By using the [`@Retry`](#using-retry-annotation) annotation
158-
- By extending the [`WithRetry`](#using-with-retry-interface) interface
157+
- By using the [`@Retry`](#retry-annotation) annotation
158+
- By extending the [`WithRetry`](#with-retry-interface) interface
159159

160160
### `@Retry` Annotation
161161

162-
The `@Retry` annotation takes a class implementing the [`WithRetry`](#using-with-retry-interface) interface as parameter,
162+
The `@Retry` annotation takes a class implementing the [`WithRetry`](#with-retry-interface) interface as parameter,
163163
and can be used to define a retry policy on a specific Service (when used as a class annotation) or Task (when used as a method annotation):
164164

165165
{% codes %}
@@ -336,8 +336,8 @@ There are multiple ways to define an execution timeout for a Task:
336336

337337
- During the [configuration](/docs/services/executors#creating-a-service-executor) of the Service Executor.
338338
- Within the implementation code of the Service itself:
339-
- By using the [`@Timeout`](#using-timeout-annotation) annotation
340-
- By extending the [`WithTimeout`](#using-with-timeout-interface) interface
339+
- By using the [`@Timeout`](#timeout-annotation) annotation
340+
- By extending the [`WithTimeout`](#with-timeout-interface) interface
341341

342342

343343
{% callout type="warning" %}
@@ -348,7 +348,7 @@ When defined in the interface, a timeout has a different meaning. It represents
348348

349349
### `@Timeout` Annotation
350350

351-
This annotation has a class implementing [`WithTimeout`](#using-with-timeout-interface) as parameter.
351+
This annotation has a class implementing [`WithTimeout`](#with-timeout-interface) as parameter.
352352

353353
It can be used as a method annotation to define a timeout on a specific task:
354354

@@ -496,6 +496,143 @@ class MyServiceImpl : MyService, WithTimeout {
496496

497497
{% /codes %}
498498

499+
### Cooperative Canceling
500+
501+
{% callout type="warning" %}
502+
503+
When a task times out, the current execution is not automatically stopped. It's your responsability to cooperate with Infinitic to cancel the task execution
504+
505+
{% /callout %}
506+
507+
Infinitic provides a thread-local `hasTimedOut` property that can be used to check if the task has timed out:
508+
509+
{% codes %}
510+
511+
```java
512+
package com.company.services;
513+
514+
import io.infinitic.tasks.Task;
515+
import io.infinitic.tasks.WithTimeout;
516+
517+
public class MyServiceImpl implements MyService, WithTimeout {
518+
MyFirstTaskOutput myFirstTask(MyFirstTaskInput input) {
519+
...
520+
while(!Task.getHasTimedOut()) {
521+
...
522+
}
523+
}
524+
525+
public Double getTimeoutSeconds() {
526+
return 100.0;
527+
}
528+
}
529+
```
530+
531+
```kotlin
532+
package com.company.services
533+
534+
import io.infinitic.tasks.Task
535+
import io.infinitic.tasks.WithTimeout
536+
537+
class MyServiceImpl : MyService, WithTimeout {
538+
override fun myFirstTask(MyFirstTaskInput input) {
539+
...
540+
while(!Task.hasTimedOut) {
541+
...
542+
}
543+
}
544+
545+
override fun getTimeoutSeconds() = 100.0
546+
}
547+
```
548+
549+
{% /codes %}
550+
551+
It is also possible to define a thread-local timeout callback to be executed when the task times out:
552+
553+
{% codes %}
554+
555+
```java
556+
package com.company.services;
557+
558+
import io.infinitic.tasks.Task;
559+
import io.infinitic.tasks.WithTimeout;
560+
561+
public class MyServiceImpl implements MyService, WithTimeout {
562+
MyFirstTaskOutput myFirstTask(MyFirstTaskInput input) {
563+
Task.onTimeOut(() -> {
564+
...
565+
});
566+
...
567+
}
568+
569+
public Double getTimeoutSeconds() {
570+
return 100.0;
571+
}
572+
}
573+
```
574+
575+
```kotlin
576+
package com.company.services
577+
578+
import io.infinitic.tasks.Task
579+
import io.infinitic.tasks.WithTimeout
580+
581+
class MyServiceImpl : MyService, WithTimeout {
582+
override fun myFirstTask(MyFirstTaskInput input) {
583+
Task.onTimeOut {
584+
...
585+
}
586+
...
587+
}
588+
589+
override fun getTimeoutSeconds() = 100.0
590+
}
591+
```
592+
593+
{% /codes %}
594+
595+
Note: The current thread is automatically canceled when the timeout is reached. To provide time to do the necessary cleanup before the thread is canceled, you can specify a grace period in the `WithTimeout` interface.
596+
597+
{% codes %}
598+
599+
```java
600+
package com.company.services;
601+
602+
import io.infinitic.tasks.WithTimeout;
603+
604+
public class MyServiceImpl implements MyService, WithTimeout {
605+
MyFirstTaskOutput myFirstTask(MyFirstTaskInput input) { /* */ }
606+
607+
MySecondTaskOutput mySecondTask(MySecondTaskInput input) { /* */ }
608+
609+
public Double getTimeoutSeconds() {
610+
return 100.0;
611+
}
612+
613+
public Double getGracePeriodAfterTimeoutSeconds() {
614+
return 5.0;
615+
}
616+
}
617+
```
618+
619+
```kotlin
620+
package com.company.services
621+
622+
import io.infinitic.tasks.WithTimeout
623+
624+
class MyServiceImpl : MyService, WithTimeout {
625+
override fun myFirstTask(MyFirstTaskInput input) { /* */ }
626+
627+
override mySecondTask(MySecondTaskInput input) { /* */ }
628+
629+
override fun getTimeoutSeconds() = 100.0
630+
631+
override fun getGracePeriodAfterTimeoutSeconds() = 5.0
632+
}
633+
```
634+
635+
{% /codes %}
499636

500637
## Good Practices
501638

0 commit comments

Comments
 (0)