# Activity Timeouts - PHP SDK

> Optimize Workflow Execution with Temporal PHP SDK - Set Activity Timeouts and Retry Policies efficiently.

## How to set Activity timeouts 

Each Activity timeout controls the maximum duration of a different aspect of an Activity Execution.

The following timeouts are available in the Activity Options.

- **[Schedule-To-Close Timeout](/encyclopedia/detecting-activity-failures#schedule-to-close-timeout):** is the maximum amount of time allowed for the overall [Activity Execution](/activity-execution).
- **[Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout):** is the maximum time allowed for a single [Activity Task Execution](/tasks#activity-task-execution).
- **[Schedule-To-Start Timeout](/encyclopedia/detecting-activity-failures#schedule-to-start-timeout):** is the maximum amount of time that is allowed from when an [Activity Task](/tasks#activity-task) is scheduled to when a [Worker](/workers#worker) starts that Activity Task.

An Activity Execution must have either the Start-To-Close or the Schedule-To-Close Timeout set.

Because Activities are reentrant, only a single stub can be used for multiple Activity invocations.

Available timeouts are:

- withScheduleToCloseTimeout()
- withStartToCloseTimeout()
- withScheduleToStartTimeout()

```php
$this->greetingActivity = Workflow::newActivityStub(
    GreetingActivityInterface::class,
    // Set Activity Timeout duration
    ActivityOptions::new()
        ->withScheduleToCloseTimeout(CarbonInterval::seconds(2))
        // ->withStartToCloseTimeout(CarbonInterval::seconds(2))
        // ->withScheduleToStartTimeout(CarbonInterval::seconds(10))
);
```

### How to set an Activity Retry Policy 

A Retry Policy works in cooperation with the timeouts to provide fine controls to optimize the execution experience.

Activity Executions are automatically associated with a default [Retry Policy](/encyclopedia/retry-policies) if a custom one is not provided.

To set an Activity Retry, set `{@link RetryOptions}` on `{@link ActivityOptions}`.
The follow example creates a new Activity with the given options.

```php
$this->greetingActivity = Workflow::newActivityStub(
    GreetingActivityInterface::class,
    ActivityOptions::new()
        ->withScheduleToCloseTimeout(CarbonInterval::seconds(10))
        ->withRetryOptions(
            RetryOptions::new()
                ->withInitialInterval(CarbonInterval::seconds(1))
                ->withMaximumAttempts(5)
                ->withNonRetryableExceptions([\InvalidArgumentException::class])
        )
);
}
```

For an executable code sample, see [ActivityRetry sample](https://github.com/temporalio/samples-php/tree/master/app/src/ActivityRetry) in the PHP samples repository.

### How to set the required Activity Timeouts 

Activity Execution semantics rely on several parameters.
The only required value that needs to be set is either a [Schedule-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout) or a [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout).
These values are set in the Activity Options.

## Activity next Retry delay 

**How to override the next Retry delay following an Activity failure using the Temporal PHP SDK**

You may throw an [`ApplicationFailure`](/references/failures#application-failure) with the `nextRetryDelay` field set.
This value will replace and override whatever the retry interval would be on the retry policy.

For example, if in an Activity, you want to base the interval on the number of attempts, you might do:

```php
$attempt = \Temporal\Activity::getInfo()->attempt;

throw new \Temporal\Exception\Failure\ApplicationFailure(
    message: "Something bad happened on attempt $attempt",
    type: 'my_failure_type',
    nonRetryable: false,
    nextRetryDelay: \DateInterval::createFromDateString(\sprintf('%d seconds', $attempt * 3)),
);
```

## How to Heartbeat an Activity 

An [Activity Heartbeat](/encyclopedia/detecting-activity-failures#activity-heartbeat) is a ping from the [Worker Process](/workers#worker-process) that is executing the Activity to the [Temporal Service](/temporal-service).
Each Heartbeat informs the Temporal Service that the [Activity Execution](/activity-execution) is making progress and the Worker has not crashed.
If the Temporal Service does not receive a Heartbeat within a [Heartbeat Timeout](/encyclopedia/detecting-activity-failures#heartbeat-timeout) time period, the Activity will be considered failed and another [Activity Task Execution](/tasks#activity-task-execution) may be scheduled according to the Retry Policy.

Heartbeats may not always be sent to the Temporal Service—they may be [throttled](/encyclopedia/detecting-activity-failures#throttling) by the Worker.

Activity Cancellations are delivered to Activities from the Temporal Service when they Heartbeat. Activities that don't Heartbeat can't receive a Cancellation.
Heartbeat throttling may lead to Cancellation getting delivered later than expected.

Heartbeats can contain a `details` field describing the Activity's current progress.
If an Activity gets retried, the Activity can access the `details` from the last Heartbeat that was sent to the Temporal Service.

Some Activities are long-running.
To react to a crash quickly, use the Heartbeat mechanism, `Activity::heartbeat()`, which lets the Temporal Server know that the Activity is still alive.
This acts as a periodic checkpoint mechanism for the progress of an Activity.

You can piggyback `details` on an Activity Heartbeat.
If an Activity times out, the last value of `details` is included in the `TimeoutFailure` delivered to a Workflow.
Then the Workflow can pass the details to the next Activity invocation.
Additionally, you can access the details from within an Activity via `Activity::getHeartbeatDetails`.
When an Activity is retried after a failure `getHeartbeatDetails` enables you to get the value from the last successful Heartbeat.

```php
use Temporal\Activity;

class FileProcessingActivitiesImpl implements FileProcessingActivities
{
    // ...
    public function download(
        string $bucketName,
        string $remoteName,
        string $localName
    ): void
    {
        $this->dowloader->downloadWithProgress(
            $bucketName,
            $remoteName,
            $localName,
            // on progress
            function ($progress) {
                Activity::heartbeat($progress);
            }
        );

        Activity::heartbeat(100); // download complete

        // ...
    }

    // ...
}
```

#### How to set a Heartbeat Timeout 

A [Heartbeat Timeout](/encyclopedia/detecting-activity-failures#heartbeat-timeout) works in conjunction with [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat).

Some Activities are long-running.
To react to a crash quickly, use the Heartbeat mechanism, `Activity::heartbeat()`, which lets the Temporal Server know that the Activity is still alive.
This acts as a periodic checkpoint mechanism for the progress of an Activity.

You can piggyback `details` on an Activity Heartbeat.
If an Activity times out, the last value of `details` is included in the `TimeoutFailure` delivered to a Workflow.
Then the Workflow can pass the details to the next Activity invocation.
Additionally, you can access the details from within an Activity via `Activity::getHeartbeatDetails`.
When an Activity is retried after a failure `getHeartbeatDetails` enables you to get the value from the last successful Heartbeat.

```php
use Temporal\Activity;

class FileProcessingActivitiesImpl implements FileProcessingActivities
{
    // ...
    public function download(
        string $bucketName,
        string $remoteName,
        string $localName
    ): void
    {
        $this->dowloader->downloadWithProgress(
            $bucketName,
            $remoteName,
            $localName,
            // on progress
            function ($progress) {
                Activity::heartbeat($progress);
            }
        );

        Activity::heartbeat(100); // download complete

        // ...
    }

    // ...
}
```
