# Tasks

## Introduction

A task is the work (method) that will be executed by a job. Defining a task is as simple as annotating a method with the `@Task` method. Let's get started and define a task that says *Hello world!*.

```java
package com.example.tasks;
import dev.doddle.core.engine.task.Task;

public class GreetingService {
    @Task()
    public void sayHello() {
        System.out.println("Hello world!");
    }
}
```

During the installation of Doddle you specify the *basePackages* path. This *basePackages* path is used to find classes that has methods annotated with the `@Task` annotation. If a method is found with this annotation then it is registered inside the *TaskRegistry* ready to be used by jobs.

In the example defined above, it is registered inside the *TaskRegistry* as **sayHello**

#### Options

You can change the name of a task and also add a description, such as:

```java
@Task(name"hello", description="This tasks says hello")
public void sayHello() {
    System.out.println("Hello world!");
}
```

This task will be registered inside the registry as **hello** instead of **sayHello**.

{% hint style="danger" %}
Task names must be unique otherwise Doddle with throw an exception. If a task is found on one server and not the other then you will run into job processing issues!
{% endhint %}

## Execution context

Arguments is data provided by a job when it is created. The task gets access to these arguments via the execution context.&#x20;

Encrypted job arguments are decrypted when a job starts executing. Access them like you would any other value.

### Arguments

The execution context has methods for retrieving an argument and also defining a default value for an argument if it does not exist.

{% hint style="danger" %}
Doddle will throw an exception if, for example, you try to fetch a string that has been stored as a number.
{% endhint %}

#### String

```java
context.argument("name").asString();
// or how about an encrypted value?
context.argument("creditCardNumber").asString();
```

Or with a default value if the argument does not exist:

```java
context.argument("name").asString("Jamie")
```

#### Numbers

Supported argument types for numbers are int, long and double.

```java
context.argument("points").asInt();
context.argument("points").asLong();
context.argument("points").asDouble();
```

Or with a default value if the argument does not exist:

```java
context.argument("points").asInt(20);
context.argument("points").asLong(20L);
context.argument("points").asDouble(0.5);
```

#### Boolean

```java
context.argument("enabled").asBoolean();
```

Or with a default value if the argument does not exist:

```java
context.argument("enabled").asBoolean(false)
```

Out of the box, doddle provides job logging to the storage provider with no configuration necessary.

The execution context provides methods to log information about the job.  There are three logging levels supported: **debug**, **info**, and **error**. Debug is the default logging level.

### Logging

Using the execution context passed into the task, let's log some messages!

```java
context.logger().info("Hello world!");
```

Or using placeholders:

```java
context.logger().info("Hello {}, you are {} years old", name, age);
```

An error message is not very useful without some context;

```java
context.logger().error("Oh no, something happened", exception);
```

#### Configuration options

You can change the default logging level. For example, if you only want to log error messages to the storage.&#x20;

During the configuration stage:

```java
client.logger(options -> options.level(ERROR))
```

### Progress

You can monitor the progress of your jobs using functionality provided by the execution context.&#x20;

You can also track the progress of your job inside the [Doddle Web Dashboard](https://jamhall.gitbook.io/doddle/web).

#### Here's an example:

```java
@Task()
public void processOrders(ExecutionContext context) {
    final var progress = context.progress(100);
    for (int i = 0; i < 100; i++) {
        progress.advance();
    }
    // or advance by a specific value...
    progress.advance(50);
    // you can also log the current percentage...
    context.logger.info("Currently processed {}% of orders", progress.percentage());
}
```

### Environment

During the configuration of Doddle, you can set environment values and these values are accessible to all jobs.

For example, let's say you set an environment value for the server called **serverId**.&#x20;

To fetch this value you would do the following:

```java
@Task()
public void processOrders(ExecutionContext context) {
    String serverId = (String) context.environment("serverId");
    context.logger.info("Job is executing on serverId: {}", serverId);
}
```
