Scheduled tasks with Hyperlambda and retry
Tags: webdev, programming, tutorial
Published: 2022-08-16 06:40:26

**Notice** - You can register a free demo Hyperlambda cloudlet at [Aista](https://aista.com) to follow this tutorial hands on and create scheduled tasks as you see fit.

Scheduled tasks implies to repeatedly execute some piece of code according to some interval. Adding retry, implies retrying execution until it succeeds. Creating scheduled tasks with Hyperlambda is extremely easy. Making sure your tasks execute using retry logic is slightly more complex, but it's quite easy once you understand the flow of things, and you learn some basic Hyperlambda. To understand our code, we'll need to analyse some of the core Hyperlambda slots first.

## Hyperlambda is async to the bone

The above implies that Hyperlambda consumes tiny amounts of operating system resources while it's waiting for tasks. If you invoke **[http.get]** to retrieve some data from another server, the thread your Hyperlambda is scheduled to run on is actually suspended and released back to the operating system. This allows your operating system to _"reuse"_ threads for different tasks, resulting in that your app as a whole can accept a _lot_ more throughput. Your app scales much better as a result.

All thread related slots are also async to the bone. This implies that if you invoke **[sleep]**, the thread is released while Hyperlambda waits.

## The Hyperlambda task scheduler

Some additional theory about the Hyperlambda task scheduler might be needed now. This helps you understand its scalability traits. A lot of task schedulers will consume your server's resources, until you've got nothing left. Hyperlambda's task scheduler does not operate like this. First of all it's using a semaphore to make sure maximum 8 tasks are executed simultaneously. If task number 9 tries to execute, it needs to wait for one of the other tasks to finish before it's given CPU time. This prevents your operating system from being _"flooded"_ with scheduled tasks executed in parallel.

In addition it never re-schedules a repeated task before the task is finished executing. So it's literally impossible to create a task that repeats often enough by itself to flood your semaphore resulting in a stack overflow, or out of memory exception. It is still possible to create _"bad code"_ that somehow exhausts your server, but it's actually very difficult, and almost requires a conscious choice from your side as a software developer.

## The code

Now that we understand the internals of Hyperlambda's task scheduler, it's time for some code.

```
.no:int:5
while
   mt
      get-value:x:@.no
      .:int:0
   .lambda
      try

         // Do stuff here ...
         // If exception, task will "retry" 5 times.
         
         // Task succeeded, "breaking" while loop!
         set-value:x:@.no
            .:int:0

      .catch

         // Task failed, retrying 5 times.
         log.error:Task failed ...
         sleep:1000
         math.increment:x:@.no

      // Task is finished, [while] loop will now abort.
```

The above code will execute the thing inside your **[try]** block, and if it's not succeeding, it will retry 5 times before giving up. Copy and paste the above code into a scheduled tasks such as illustrated below.

![A scheduled Hyperlambda task](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mkxtq2jhmku3damrbi88.jpg)

At this point, all we need to do is to schedule or task. This is done by clicking the clock icon in the bottom right corner of your task, and choosing a repetition pattern.

![Scheduling your Hyperlambda task](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaj497t70u207isyoenf.jpg)

The above schedules your task to execute with a 5 day interval. There are repetition patterns for everything ranging from _"1st of every month"_ to _"every Tuesday and Thursday"_. Below are the basic building blocks for creating repeating tasks.

### Unit repetition

This repetition is in the form of `n.unit`. `n` is a number, and unit can be any of the following values.

* seconds
* minutes
* hours
* days
* weeks
* months

Creating a pattern such as for instance `5.weeks` implies your task will execute once and then wait for 5 weeks before executing again.

### Weekday repetition

This pattern resembles the following; `ww.HH.mm.ss`. The parts implies the following in order of appearance.

* Weekdays
* Hours
* Minutes
* Seconds

The weekday part can pipe multiple weekdays together, allowing you to use the following pattern `Tuesday|Thursday.23.55.00` to execute your task every Tuesday and Thursday 5 minutes to midnight. Weekdays can have double asterisk as its value, implying _"every weekday"_. This allows you to declare a pattern such as follows `**.05.00.00` to execute the task every day at 5AM in the morning.

### Monthly repetition

This pattern is as follows `MM.dd.HH.mm.ss` and the entities implies in order of appearance the following.

* Month
* Day of month
* Hours
* Minutes
* Seconds

To create a task that executes only in February the 5th at 7AM, you could use values such as follows `02.05.07.00.00`. Month can be piped just as weekdays above, allowing you to supply multiple months such as this; `01|02|03.05.07.00.00`. The last pattern executes January, February and March the 5th, at 7AM in the morning.

The MM, dd and ww values in both of the above repetition patterns can have `**` as their value implying _"all values"_.

## Ask us for help

This article was created because one of our partners had a specific use case needing _"HangFire functionality"_. Instead of explaining to him directly, I chose to write an article where I solved his use case. If you have some problem related to Hyperlambda or Magic, let us know, and we'll help you out :)