# Report Scheduler

Let's say your web app allows users to schedule reports to email off. These items are configurable and the user can add or remove them at any time.

* The front-end web app saves a database record back with all the information needed to run the specific report and it's parameters.
* Then the [Scheduler](https://docs.perigee.software/core-modules/event-sources/scheduled-logic/scheduler) reads the table for those database records every few minutes and updates, removes, reschedules any changed items.
* You get a simple callback when it's time to execute the event task

### Demo Scheduler

The demo below hooks up everything but actually generating reports, and [emailing](https://docs.perigee.software/core-modules/alert-managers/email) them off.&#x20;

* The `RunType` argument could easily contain what reports to generate.
* The `RunArgs` could easily contain additional user information like who it's being sent to, a database ID of the job to lookup, etc. &#x20;

{% code lineNumbers="true" %}

```csharp
PerigeeApplication.ApplicationNoInit("Demo Scheduler", (c) =>
{
   
    //Declare a new memory source, remember to use a single instance of memory/file based sources or locking can occur
    using var MemSource = new MemoryScheduledSource("memSource.json", c.CTS.Token);

    //Add scheduled items.
    //If this was something like a DatabaseScheduledSource, we obviously would control these records from the database, not here.
    MemSource.AddIfNotExists(GenericScheduledItem<ushort>.MemoryItem(0, "A scheduler, 15sec", "A", "a;b;c", "*/15 * * * * *", TimeZoneInfo.Local));
    MemSource.AddIfNotExists(GenericScheduledItem<ushort>.MemoryItem(1, "B scheduler, 45sec", "B", "b;c;d", "45 * * * * *", TimeZoneInfo.Local));

    //Add a scheduler with the MemorySource, a single callback is given for anything required to run (multi-threaded)
    c.AddScheduler("Main", MemSource, (ct, l, item) => { 
        if (item.GetRunType() == "A")
        {
            l.LogInformation("Running A with {args}", item.GetRunArgs());
        }
        else if (item.GetRunType() == "B")
        {
            l.LogInformation("Running B with {args}", item.GetRunArgs());
        }

    });

});
```

{% endcode %}

{% hint style="info" %}
The demo code uses the [**`Memory Scheduler`**](#memory-source) as it does not require a remote source. Typically speaking you would tie the event task descriptions back to a database record (like the MSSQL Scheduler Source).
{% endhint %}

* <mark style="color:blue;">**Line 5**</mark> - Declare a new event source. This demo uses the memory scheduler.
* <mark style="color:blue;">**Line 9-10**</mark> - Add the two scheduled items, A, and B, to schedule and execute
* <mark style="color:blue;">**Line 13**</mark> - Add a scheduler using the source we defined, and declare the callback.
  * You're given a <mark style="color:orange;">**CancellationToken**</mark> for respecting graceful shutdown event.
  * An <mark style="color:orange;">**ILogger**</mark> for logging to the system and defined sink sources.
  * And the <mark style="color:orange;">**GenericScheduledItem\<ushort>**</mark> Which is the interfaced item that allows you to access it's definition values.
* <mark style="color:blue;">**Line 14**</mark> - You can execute or perform any tasks you need. Like generating a report with parameters.
  * You can see the call to `GetRunType()`. There's also `GetRunArgs()`, `GetLastRunDate()`, `GetName()`, etc.

##
