> For the complete documentation index, see [llms.txt](https://docs.perigee.software/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.perigee.software/core-modules/utility-classes/perigee-utility-class.md).

# Perigee Utility Class

## Block Until

This handy method takes a CRON string and is an easy way of creating an awaitable task. It returns True if the await finished without being cancelled by the optional token.

```csharp
//Async wait until the 0th second of every 5th minute
await PerigeeUtil.BlockUntil("0 */5 * * * *");

//Or for non async methods
PerigeeUtil.BlockUntil("0 */5 * * * *").GetAwaiter().GetResult();

//Block until the next 5 minute mark, or 10 seconds. Whichever comes first
CancellationTokenSource CTSource = new CancellationTokenSource();
CTSource.CancelAfter(TimeSpan.FromSeconds(10));
var done = PerigeeUtil.BlockUntil("*/5 * * * *", null, CTSource.Token).GetAwaiter().GetResult();
```

## Retry and Rety Async

One of the utility class methods is a <mark style="color:blue;">**`Retry`**</mark>and <mark style="color:blue;">**`RetryAsync`**</mark>. They provide an easy ability to retry <mark style="color:red;">**on exception thrown**</mark> with a delay.&#x20;

The response from these classes is a Tuple where&#x20;

* <mark style="color:blue;">**`Item1`**</mark> is a `boolean` indicating if it was a success(true), or failed the maximum number of times (false).
* <mark style="color:blue;">**`Item2`**</mark> is the exception thrown if it was not a succeed

```csharp
PerigeeApplication.ApplicationNoInit("CancelTokens", (c) => {

    c.AddRecurring("Recurring", (ct, l) => {

        //This will be tried 5 times, with 10 seconds between retries. 
        Tuple<bool, Exception> Retry = PerigeeUtil.Retry(5, (i) => {

            bool Success = false;
            if (Success == false)
            {
                throw new Exception("Do or do not, there is a retry");
            }

        }, 10000);

        if (!Retry.Item1)
        {
            l.LogError(Retry.Item2, "Retries exceeded");
        }

    
    });
});
```

## RetryExponentialBackoff

Another retry strategy is the Exponential Backoff method. Unlike a constant delay between retries, this method progressively increases the delay (incorporating jitter) to prevent overwhelming a remote system with requests.&#x20;

You can define both a base delay (in milliseconds) and a maximum delay (in milliseconds) to ensure the delay between requests scales appropriately.

```csharp
PerigeeApplication.ApplicationNoInit("Backoff", (c) => {

    c.AddRecurring("Exponential", (ct, l) => {

        //Log out the backoff delays, logging them is an easy way to test and see what times are going to be used.
        l.LogInformation("Backoff times: {time}", string.Join(", ", PerigeeUtil.GetExponentialBackoffDelays(20, 1000, 1800000)));

        // Use the .RetryExponential to follow the same times as shown above, with a small jitter to each delay
        PerigeeUtil.RetryExponentialBackoff(20, (i) => {

            l.LogInformation("Retry number {i}", i);
            throw new Exception("Throwing to cause another retry");

        }, 1000, 1800000);

    });
    
});

/*
Backoff times: 956, 2102, 4469, 8470, 17127, 31337, 57203, 152968, 234956, 575255, 901233, 1645927, 1800000, 1800000, 1800000, 1800000, 1800000, 1800000, 1800000, 1800000
*/
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.perigee.software/core-modules/utility-classes/perigee-utility-class.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
