# Heavy Operations

A single request gets a single time budget, the [execution timeout](/advance-usage/bounding-execution). Everything the server does for that request draws on it: parsing the Terms you sent, running the operation, and converting the result into the response format you asked for.

For most calls this is invisible. It becomes relevant when the operation is heavy **and** you ask for the result as a regex pattern, because both stages then draw on the same budget.

## Why patterns are the expensive part

Turning an automaton back into a regular expression has many correct answers, and they differ enormously in readability. `.*abc` and a page-long equivalent describe the same language.

The server therefore works in two phases:

1. **A baseline conversion** produces a correct regex quickly.
2. **Improvement passes** then look for a shorter, more readable equivalent, and keep the smallest one they can prove correct.

The second phase produces the readable patterns, and it is optional: once the baseline exists a correct answer is already available. If the time budget runs out at that point, the server **stops searching and returns the best pattern found so far** rather than failing the request.

<Callout type="note">
The language of the result is always exact. A conversion cut short by the budget affects readability only.
</Callout>

## Effect on a heavy call

If a heavy intersection consumes most of the budget, the improvement passes receive whatever remains, which may be almost nothing. The returned pattern is correct but considerably longer and harder to read than the same pattern computed with the full budget available.

Raising `executionTimeout` helps only up to your plan's maximum, and it increases the latency of the request as a whole.

## Split the work across two calls

Ask the heavy operation for **FAIR**, then fetch the pattern in a second call. Each request then has a full budget of its own.

<CodeTabs defaultValue="java">
<CodeTabs.Tab value="java" label="Java">
```java
RegexSolverClient client = RegexSolverClient.builder()
    .apiToken(System.getenv("REGEXSOLVER_API_TOKEN"))
    .build();

Term a = Term.regex(".*abc.*def.*");
Term b = Term.regex(".*(ghi|jkl).*");

// 1. The heavy operation, returned as FAIR: no pattern conversion happens here
OperationOptions options = OperationOptions.builder()
    .responseFormat(ResponseFormat.FAIR);
Term result = client.intersection(List.of(a, b), options);

// 2. A separate request converts it, with a full budget for the improvement passes
String pattern = client.getPattern(result);
```
</CodeTabs.Tab>

<CodeTabs.Tab value="javascript" label="JavaScript">
```javascript
const client = new RegexSolverClient({ apiToken: process.env.REGEXSOLVER_API_TOKEN });

const a = Term.regex(".*abc.*def.*");
const b = Term.regex(".*(ghi|jkl).*");

// 1. The heavy operation, returned as FAIR: no pattern conversion happens here
const result = await client.intersection(a, b, { responseFormat: ResponseFormat.FAIR });

// 2. A separate request converts it, with a full budget for the improvement passes
const pattern = await client.getPattern(result);
```
</CodeTabs.Tab>

<CodeTabs.Tab value="python" label="Python">
```python
client = RegexSolverClient(api_token=os.getenv("REGEXSOLVER_API_TOKEN"))

a = Term.regex(r".*abc.*def.*")
b = Term.regex(r".*(ghi|jkl).*")

# 1. The heavy operation, returned as FAIR: no pattern conversion happens here
result = client.intersection(a, b, response_format=ResponseFormat.FAIR)

# 2. A separate request converts it, with a full budget for the improvement passes
pattern = client.get_pattern(result)
```
</CodeTabs.Tab>
</CodeTabs>

The trade-off is one extra request against your monthly quota. Spend it when the pattern is going to be read by a person or stored somewhere long-lived.

## When you do not need the second call

* **Chaining operations.** Keep every intermediate result in FAIR and convert once at the very end, if at all. FAIR skips regex parsing on the way in, so chained calls are faster as well as more readable at the end. See [Term's Format](/core-concepts/terms-format).
* **Leaving the format alone.** The default response format returns whatever the operation naturally produced and converts nothing, so it never triggers a pattern conversion. The contention described above only arises when you explicitly ask for `regex`.
* **Light operations.** A pattern conversion that finishes well inside the budget gains nothing from being split out.

## When the request fails instead

Returning the best pattern so far needs a baseline to fall back on. If the budget runs out before even the baseline conversion completes, there is nothing correct to return and the request fails with `TimeoutExceeded`. The same applies when the operation itself is what runs out of time.

Splitting the call is the first thing to try here too, since it gives each half a full budget. See [Bounding Execution](/advance-usage/bounding-execution) for the timeout itself and [Error Handling](/error-handling) for the errors.
