Skip to content

add execution timeout cooperation #20

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions src/pages/docs/services/batch.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Here are some common use cases:

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

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

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

```kotlin
@Batch
fun sendBatchEmails(emails: Map<String, EmailRequest>): Map<String, Boolean> {
fun sendEmails(emails: Map<String, EmailRequest>): Map<String, Boolean> {
val results = emailService.sendbatch(emails.values)
return emails.mapValues { (_, email) -> results.contains(email.id) }
}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/services/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The `io.infinitic.tasks.Task` class provides the following static properties:
| [`meta`](#meta) | Map\<String, ByteArray\> | Metadata provided when dispatching the task |
| [`retryIndex` ](#retry-index) | Integer | Number of times the task was automatically retried |
| [`retrySequence`](#retry-sequence) | Integer | Number of times the task was manually retried |
| [`attempts`](#attempts) | List<AttemptException> | list of previous `AttemptException` |
| [`lastError`](#last-error) | TaskFailure? | The last error that occurred during the task execution |
| `batchKey` | String? | If any, the [batch key](/docs/services/batched#optional-batch-key) provided when the task was dispatched |
| `client` | InfiniticClient | An [InfiniticClient](/docs/components/terminology#clients) that can be used inside the task |

Expand Down
149 changes: 143 additions & 6 deletions src/pages/docs/services/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,12 @@ There are multiple ways to define a retry policy for a Service:

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

### `@Retry` Annotation

The `@Retry` annotation takes a class implementing the [`WithRetry`](#using-with-retry-interface) interface as parameter,
The `@Retry` annotation takes a class implementing the [`WithRetry`](#with-retry-interface) interface as parameter,
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):

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

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


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

### `@Timeout` Annotation

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

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

Expand Down Expand Up @@ -496,6 +496,143 @@ class MyServiceImpl : MyService, WithTimeout {

{% /codes %}

### Cooperative Canceling

{% callout type="warning" %}

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

{% /callout %}

Infinitic provides a thread-local `hasTimedOut` property that can be used to check if the task has timed out:

{% codes %}

```java
package com.company.services;

import io.infinitic.tasks.Task;
import io.infinitic.tasks.WithTimeout;

public class MyServiceImpl implements MyService, WithTimeout {
MyFirstTaskOutput myFirstTask(MyFirstTaskInput input) {
...
while(!Task.getHasTimedOut()) {
...
}
}

public Double getTimeoutSeconds() {
return 100.0;
}
}
```

```kotlin
package com.company.services

import io.infinitic.tasks.Task
import io.infinitic.tasks.WithTimeout

class MyServiceImpl : MyService, WithTimeout {
override fun myFirstTask(MyFirstTaskInput input) {
...
while(!Task.hasTimedOut) {
...
}
}

override fun getTimeoutSeconds() = 100.0
}
```

{% /codes %}

It is also possible to define a thread-local timeout callback to be executed when the task times out:

{% codes %}

```java
package com.company.services;

import io.infinitic.tasks.Task;
import io.infinitic.tasks.WithTimeout;

public class MyServiceImpl implements MyService, WithTimeout {
MyFirstTaskOutput myFirstTask(MyFirstTaskInput input) {
Task.onTimeOut(() -> {
...
});
...
}

public Double getTimeoutSeconds() {
return 100.0;
}
}
```

```kotlin
package com.company.services

import io.infinitic.tasks.Task
import io.infinitic.tasks.WithTimeout

class MyServiceImpl : MyService, WithTimeout {
override fun myFirstTask(MyFirstTaskInput input) {
Task.onTimeOut {
...
}
...
}

override fun getTimeoutSeconds() = 100.0
}
```

{% /codes %}

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.

{% codes %}

```java
package com.company.services;

import io.infinitic.tasks.WithTimeout;

public class MyServiceImpl implements MyService, WithTimeout {
MyFirstTaskOutput myFirstTask(MyFirstTaskInput input) { /* */ }

MySecondTaskOutput mySecondTask(MySecondTaskInput input) { /* */ }

public Double getTimeoutSeconds() {
return 100.0;
}

public Double getGracePeriodAfterTimeoutSeconds() {
return 5.0;
}
}
```

```kotlin
package com.company.services

import io.infinitic.tasks.WithTimeout

class MyServiceImpl : MyService, WithTimeout {
override fun myFirstTask(MyFirstTaskInput input) { /* */ }

override mySecondTask(MySecondTaskInput input) { /* */ }

override fun getTimeoutSeconds() = 100.0

override fun getGracePeriodAfterTimeoutSeconds() = 5.0
}
```

{% /codes %}

## Good Practices

Expand Down