Skip to content

plugin sdk server management

Andre Lafleur edited this page Aug 25, 2026 · 10 revisions

About plugin server management

Plugins run as roles that can be assigned to multiple servers for high availability and failover.

Server assignment model

Plugin Role
    ↓
Assigned to Server A (Priority 1)
Assigned to Server B (Priority 2)
Assigned to Server C (Priority 3)
    ↓
Runs on highest priority available server
    ↓
Fails over to next server if current fails

Key concepts:

  • Plugins are roles that can run on multiple servers
  • Priority determines which server runs the plugin
  • Automatic failover to next priority server on failure
  • Manual server selection supported
  • Server rejection allows plugins to control where they run

Server assignment

Adding servers

Servers are assigned to plugin roles in Config Tool:

Path: System > Roles > [Plugin Role] > Properties > Servers

Administrators can:

  • Add/remove servers
  • Set server priorities
  • Enable/disable automatic failover
  • Manually select running server

Server priority

Servers have priority levels (1 = highest):

Priority 1: Primary server (preferred)
Priority 2: Secondary server (backup)
Priority 3: Tertiary server (last resort)

Automatic failover behavior:

  • Plugin runs on highest priority available server
  • If that server fails, plugin fails over to next priority
  • When higher priority server recovers, plugin can failover back (if enabled)

High availability strategies

Force execution by priority

Automatically switches to highest priority server when available:

protected override void OnPluginLoaded()
{
    // Enable automatic priority-based failover
    SetForceExecutionByPriority(true);
}

When enabled:

  • Plugin always runs on highest priority available server
  • Automatically fails back to higher priority servers when they recover
  • Good for active-passive failover scenarios

When disabled:

  • The role stays on its current server and does not automatically switch back to a higher-priority server when one recovers
  • Moving the role to a specific server requires manual selection
  • The plugin runs on only one server at a time

Manual server selection

Administrator manually controls which server runs the plugin:

// Get current server
Guid currentServer = GetCurrentServer();

// Manually switch to different server
SetCurrentServer(targetServerGuid);

Use cases:

  • Maintenance operations
  • Load balancing
  • Testing
  • Troubleshooting

Server management methods

Available through Plugin base class:

GetCurrentServer()

Returns GUID of server currently running the plugin:

protected override void OnPluginLoaded()
{
    Guid serverGuid = GetCurrentServer();
    
    var server = Engine.GetEntity<Server>(serverGuid);
    Logger.TraceInformation($"Plugin running on server: {server.Name}");
    
}

Returns:

  • Server GUID

GetServersInfo()

Returns information about all assigned servers:

protected override void OnPluginLoaded()
{
    Dictionary<Guid, ServerInfos> servers = GetServersInfo();

    foreach (var kvp in servers)
    {
        Guid serverGuid = kvp.Key;
        ServerInfos info = kvp.Value;

        Logger.TraceInformation($"Server: {serverGuid}, Order: {info.Order}");
    }
}

ServerInfos properties:

  • Order - Server priority order (lower numbers = higher priority)
  • NetworkBinding - Network binding configuration for the server

AddServer()

Programmatically add a server to the role:

private void AddBackupServer(Guid serverGuid)
{
    AddServer(serverGuid);
    Logger.TraceInformation($"Added server {serverGuid} to plugin role");
}

Considerations:

  • Server must exist in system
  • Duplicate adds are ignored
  • Priority assigned automatically (lowest available)
  • Config Tool reflects change immediately

RemoveRoleServer()

Remove a server from the role:

private void RemoveServer(Guid serverGuid)
{
    RemoveRoleServer(serverGuid);
    Logger.TraceInformation($"Removed server {serverGuid} from plugin role");
}

Considerations:

  • The method removes the server from the role's server list; it does not block removing the server the role is currently running on, and it does not require switching to another server first
  • Removing the server that currently runs the role affects where the role runs, so change the server list deliberately
  • Config Tool reflects change immediately

SetCurrentServer()

Manually switch to specific server:

private void FailoverToBackup(Guid backupServerGuid)
{
    Logger.TraceInformation($"Failing over to backup server {backupServerGuid}");
    SetCurrentServer(backupServerGuid);
}

Behavior:

  • Stops plugin on current server
  • Starts plugin on target server
  • May cause brief service interruption
  • Target server must be in role's server list

Important

SetCurrentServer throws if ForceExecutionByPriority is enabled. Disable it first with SetForceExecutionByPriority(false) before manually switching servers.

SetForceExecutionByPriority()

Control automatic priority-based failover:

protected override void OnPluginLoaded()
{
    // Enable automatic failover to highest priority server
    SetForceExecutionByPriority(true);
}

Effect:

  • true - Auto-failover to highest priority available server
  • false - Stay on current server until failure

GetServerCertificate()

Returns the X509 certificate used by the server hosting the plugin:

protected override void OnPluginLoaded()
{
    X509Certificate2 cert = GetServerCertificate();

    if (cert != null)
    {
        Logger.TraceInformation($"Server certificate subject: {cert.Subject}");
        Logger.TraceInformation($"Certificate expires: {cert.NotAfter}");
    }
}

Returns:

  • X509Certificate2 - A clone of the server's certificate
  • null - If no certificate is available

Usage notes:

  • Used for validating server identity or establishing secure connections
  • The certificate belongs to the Security Center server hosting the plugin

GetAvailableNetworkCards()

Returns network cards available on each server assigned to the role:

protected override void OnPluginLoaded()
{
    Dictionary<Guid, List<NetworkCard>> networkCards = GetAvailableNetworkCards();

    foreach (var kvp in networkCards)
    {
        Guid serverGuid = kvp.Key;
        List<NetworkCard> cards = kvp.Value;

        var server = Engine.GetEntity<Server>(serverGuid);
        Logger.TraceInformation($"Server {server.Name} has {cards.Count} network cards:");

        foreach (var card in cards)
        {
            Logger.TraceInformation($"  MAC: {card.MacAddress}, IP: {card.IpAddress}");
        }
    }
}

Returns:

  • Dictionary<Guid, List<NetworkCard>> - Server GUID mapped to list of network cards
  • null - If the role entity cannot be found

NetworkCard properties:

  • MacAddress - The MAC address of the network card (or "Any" for default binding)
  • IpAddress - The IPv4 address of the network card

Usage notes:

  • Always includes an "Any" option with empty IP address for default network binding
  • Use to allow administrators to select specific network interfaces
  • Useful for plugins that need to bind to specific network adapters

SetNetworkCard()

Sets the network card binding for a specific server:

private void ConfigureNetworkBinding(Guid serverGuid, NetworkCard selectedCard)
{
    bool success = SetNetworkCard(serverGuid, selectedCard);

    if (success)
    {
        Logger.TraceInformation($"Network card set to {selectedCard.MacAddress}");
    }
    else
    {
        Logger.TraceError("Failed to set network card");
    }
}

Parameters:

  • serverId - The GUID of the server to configure
  • networkCard - The network card to bind to

Returns:

  • true - Network card was set successfully
  • false - Role entity not found

Usage notes:

  • Setting MAC address to "Any" clears the network binding (uses default)
  • Changes are persisted to the role configuration
  • The server must be in the role's server list
  • Use with GetAvailableNetworkCards() to present valid options

Server rejection

Plugins can reject servers that don't meet requirements:

RejectServer()

Reject current server and trigger failover:

protected override void OnPluginLoaded()
{
    if (!ValidateServerRequirements())
    {
        Guid currentServer = GetCurrentServer();
        RejectServer(currentServer, "Required hardware not available");
        
        Logger.TraceWarning($"Rejected server {currentServer}");
        return; // Don't continue initialization
    }
    
    // Server meets requirements
    AcceptServer(GetCurrentServer());
}

When rejected:

  • Plugin stops on rejected server
  • Security Center attempts to start plugin on next priority server
  • Rejection reason logged and visible in Config Tool
  • Server remains in role's server list but marked as rejected

AcceptServer()

Explicitly accept current server:

protected override void OnPluginLoaded()
{
    if (ValidateServerRequirements())
    {
        AcceptServer(GetCurrentServer());
        Logger.TraceInformation("Server accepted");
    }
}

When to use:

  • After validating server requirements
  • Confirms plugin can run on this server
  • Good practice for explicit acceptance

Server requirements validation

Common validation scenarios

Hardware requirements:

private bool ValidateServerRequirements()
{
    // Check for required hardware
    if (!IsSerialPortAvailable())
    {
        Logger.TraceError("Serial port not available");
        return false;
    }
    
    // Check for required network access
    if (!CanReachExternalSystem())
    {
        Logger.TraceError("Cannot reach external system");
        return false;
    }
    
    return true;
}

Resource requirements:

private bool ValidateServerRequirements()
{
    // Check available memory
    var availableMemory = GetAvailableMemory();
    if (availableMemory < RequiredMemoryMB)
    {
        Logger.TraceError($"Insufficient memory: {availableMemory}MB < {RequiredMemoryMB}MB");
        return false;
    }
    
    // Check disk space
    var availableDisk = GetAvailableDiskSpace();
    if (availableDisk < RequiredDiskSpaceGB)
    {
        Logger.TraceError($"Insufficient disk space");
        return false;
    }
    
    return true;
}

Software requirements:

private bool ValidateServerRequirements()
{
    // Check for required assemblies
    if (!IsAssemblyAvailable("ThirdParty.Hardware.dll"))
    {
        Logger.TraceError("Required assembly not found");
        return false;
    }
    
    // Check for required services
    if (!IsServiceRunning("RequiredService"))
    {
        Logger.TraceError("Required Windows service not running");
        return false;
    }
    
    return true;
}

Server lifecycle events

Plugin moving between servers

Plugin running on Server A
    ↓
Priority changes or the role is moved
    ↓
1. Dispose() called on Server A
    ↓
2. Plugin stops on Server A
    ↓
3. Constructor called on Server B
    ↓
4. Initialize() called on Server B
    ↓
5. OnPluginLoaded() called on Server B
    ↓
6. OnPluginStart() called on Server B
    ↓
Plugin running on Server B

When Server A fails abruptly, no further code runs there: Dispose() is not called, and the sequence starts at step 3 on Server B. Any work in flight on Server A is abandoned wherever it stopped.

Important

  • Complete lifecycle executes on each server
  • No state automatically transferred between servers
  • Must persist state externally (database, file share)
  • Each instance is independent

Persisting state across failover

Use database:

public class MyPlugin : Plugin, IPluginDatabaseSupport
{
    protected override void OnPluginStart()
    {
        // Load state from database
        LoadStateFromDatabase();
    }
    
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Save state to database
            SaveStateToDatabase();
        }
    }
}

Dispose runs only when the priority changes or the role is moved. When the server fails, Dispose does not run and everything since the last save is lost. Save state when it changes, as the configuration example below does, and treat the save in Dispose as a final write, not the only one.

Use configuration:

protected override void OnPluginLoaded()
{
    // Load state from configuration
    var config = LoadConfiguration();
    RestoreState(config.SavedState);
}

private void OnStateChanged()
{
    // Persist state to configuration
    var config = LoadConfiguration();
    config.SavedState = CaptureState();
    UpdateConfiguration(config);
}

Distributing work across servers

A plugin role runs on a single server at a time. SetForceExecutionByPriority(false) only stops the role from switching back to a higher-priority server when one recovers; it does not run the plugin on additional servers.

If your plugin must process work concurrently on more than one server, use a workload distribution design outside the single-role failover model.

See also

Platform SDK

Plugin SDK

Workspace SDK

Media SDK

Macro SDK

Web SDK

Synergis RIO

Media Gateway

Genetec Web Player

Clone this wiki locally