Page cover image

🪡Thread Registry

Most of the Demos have the property named c when registering a new PerigeeApplication. The c simply stands for config. Let's take a look at how you can access and control the managed threads within an application.

PerigeeApplication.ApplicationNoInit("Demo", (c) => //"c" here is the registry
{     

});

Properties

The Cancellation Token

There is a single "global" token that all other tokens are joined to. This is a great place to listen for application shutdown as it's cancelled the moment a SIG_ABORT or CONTROL-C event is received.

To get the globally registered cancellation token, it's available as such:

//Use method
c.GetCancellationToken()

//OR go directly to the source
c.CTS.Token;

Names, configurations

AppName - is available for the registered application name, if used for logging or custom logic.

Args[] - is available if passed into the constructor, and is the application start parameters.

Configuration - is the IConfiguration that was loaded and built after it's Configuration phase.

ServiceProvider - The IServiceProvider after service build configuration

Event_ConfigurationUpdated - Is the event handler for subscribing to hot-reloads. You may also use the helper method c.ConfigUpdatedEvent((nconfig) => {}).

RegisteredTaskCount - The number of registered threads

Hosted

Hosted application task is respected and shut down alongside Perigee.

HostTask - When hosting an API application, supply the host task and it is stored here. The demo for this functionality can be seen here:

Perigee With .NET Hosting

Secure properties

SecureValueKey - The secure key

SecureValueIV - The secure IV

SecureValueSource - The secure source, either args, environment, or direct.

To see the demo for this, check out:

Hello Configuration

Configuration Methods

IConfiguration

Configure

To override the IConfiguration, call ConfigureConfiguration(). This builds the IConfiguration with the default options and whatever you've added to the builder.

PerigeeApplication.ApplicationNoInit("Configuration", (c) => {

    c.ConfigureConfiguration((cb, env) => {
        cb.AddKeyPerFile("keyDirectory");
    });

});

Reload Configuration Event

PerigeeApplication.ApplicationNoInit("Configuration", (c) => {

    c.ConfigUpdatedEvent((config) => {
        c.GetLogger<_PerigeeStartup>().LogInformation("Config updated");
    });

});

Get a configuration

PerigeeApplication.ApplicationNoInit("Configuration", (c) => {

    //Get a value from the config by path
    var Name = c.GetValue<string>("HelloConfig:Name");
    
    //Get a class of the configuration section
    HelloConfig hc = c.GetConfigurationAs<HelloConfig>("HelloConfig");


});

public class HelloConfig
{
    public string Name { get; set; }
    public int Year { get; set; }
    public List<string> Tags { get; set; }
}
/*
 
"HelloConfig": {
    "Name": "HAL 9000",
    "Year": 2001,
    "Tags": [ "Heuristic", "Algorithmic" ]
  },
 
 */

IServiceProvider

If you need to configure the service provider, do so with the ConfigureServices() callback.

Configure and get service

PerigeeApplication.ApplicationNoInit("Configuration", (c) => {

    c.ConfigureServices((sc, env) => {
        sc.AddSingleton((isp) => new HelloConfig());
    });

    var hc = c.ServiceProvider.GetRequiredService<HelloConfig>();

});

Windows Startup

Registering

If you want to register an autostart for the windows platform, it does so by adding values to the registry. The app MUST be run with administrative privileges the first time this key is set.

c.RegisterStartup();

Thread Methods

GetThreads

Get all threads from the management system

Example:

c.GetThreads();

RestartAllThreads

Restarts all threads in the system. This will start stopped threads, it's intended to perform a full reboot of the application and all of the threads, regardless of their current state.

Example:

c.RestartAllThreads();

You could use the RunTime property to only restart threads that haven't been restarted in a certain period of time:

Example:

c.GetThreads().Where(f => f.RunTime > TimeSpan.FromSeconds(30)).ToList().ForEach(f =>
{
        l.LogInformation("Restarting thread {n}", f.Name);
        f.StartOrRestart();
});

StartOrRestart

Starts or restarts a thread with the specified name.

Example:

c.StartOrRestart("MyThread");

Start

Starts a thread with the specified name.

Example:

c.Start("MyThread");

Stop

NOTE We highly recommend using QueueStop() over Stop(). The reason is that Stop is not thread safe, and may cause issues. It exists only for niche, same thread operation. Use with caution!

Example:

c.Stop("MyThread");

QueueStop

Queues the stop of a thread, waiting for the task to complete.

Example:

c.QueueStop("MyThread", true);

IsRunning

Checks whether a thread with the specified name is running.

Example:

bool isRunning = c.IsRunning("MyThread");

StartIfNotRunning

Starts a thread with the specified name if it is not already running.

Example:

bool started = c.StartIfNotRunning("MyThread");

GetThread

Gets a thread with the specified name, if it exists. Use with caution.

Example:

ManagedThread myThread = c.GetThread("MyThread");

ContainsThreadByName

Checks if the collection contains a thread with the specified name.

Example:

bool result = c.ContainsThreadByName("threadName");

ExecuteCRONNow

Executes a CRON thread immediately by its name. Optionally, you can provide a callback to be invoked when the CRON operation is completed and the number of seconds to wait for a start operation

Example:

bool result = c.ExecuteCRONNow("threadName", () => Console.WriteLine("CRON completed"), 3000);

Add a custom managed thread

The best example of this is shown here:

Extending - Threads

You can link managed threads to configuration values in one of two ways:

  1. Use the handy .LinkToConfig() method immediately following the thread

  2. Use the .LinkConfigToThread() method somewhere later

PerigeeApplication.ApplicationNoInit("Configuration", (c) => {

    //Add a CRON thread that is not started by default. Then link it to the HelloConfig:Enabled boolean
    c.AddCRON("MyThread", "0 0 1 1 *", 
        (ct, l) => { 

            l.LogInformation("Running"); 

        }, 
        started: false).LinkToConfig("HelloConfig:Enabled");

    //You may also provide thread linking later:
    c.LinkConfigToThread("HelloConfig:Enabled", "MyThread");
    

});

Agent Methods

Agents are explained fully over here:

Sync Agent

Get agents

To get an agent after it's been added to the system, call GetAgent().

PerigeeApplication.ApplicationNoInit("Agent", (c) => {

    //Add an agent to run every 2 hours, at most 4 times a day 
    c.AddAgent("MyAgent", "Agent1", "Main", new SyncAgentSourceMemory("AgentDemo.json", c.GetCancellationToken()), AgentRunCondition.RunIfPastDue, (c) => c.SetSyncLimitPerDay(4).SetSync(TimeSpan.FromHours(2)),
        (ct, l, exec) =>
        {
            return exec.Complete(DateTimeOffset.UtcNow.AddHours(1));
        }, null);

    //Get the agent
    var agent = c.GetAgent("MyAgent");

    c.ConfigureAgent("MyAgent", (c) => c.SetSync(TimeSpan.FromSeconds(20)));
    //(MyAgent) Agent1(Main) Next Check in 18 seconds

});

Configure agents

To reconfigure an agent after it's been added to the system:

PerigeeApplication.ApplicationNoInit("Agent", (c) => {

    //Add an agent to run every 2 hours, at most 4 times a day 
    c.AddAgent("MyAgent", "Agent1", "Main", new SyncAgentSourceMemory("AgentDemo.json", c.GetCancellationToken()), AgentRunCondition.RunIfPastDue, (c) => c.SetSyncLimitPerDay(4).SetSync(TimeSpan.FromHours(2)),
        (ct, l, exec) =>
        {
            return exec.Complete(DateTimeOffset.UtcNow.AddHours(1));
        }, null);

    //Call configure, changing the timespan check to 20 seconds.
    c.ConfigureAgent("MyAgent", (c) => c.SetSync(TimeSpan.FromSeconds(20)));
    
    //You'll see the log of the next check event:
    //   (MyAgent) Agent1(Main) Next Check in 18 seconds

});

Queue Remote Refresh

Queues an agent for remote refresh. The parameters are:

  • The agent name.

  • A boolean to say whether or not to queue if the current agent is executing.

    • If TRUE, it will wait for the current execution to finish and then trigger another exeucution.

    • If FALSE, it will not trigger another execution, but return.

  • An optional wait time before giving up. If the wait time is not supplied, it will wait indefinitely.

Example:

c.Agent_QueueRemoteRefresh("AgentName", true, TimeSpan.FromSeconds(30));

Last updated