How to implement a comprehensive, scalable solution for granular updates across many servers?

ImportantThe following article uses options that are available starting with the Professional edition and project type.

1. Scenario

How to implement a comprehensive, scalable solution for granular updates across many servers using the Updater. It covers the conceptual flow, a sample updateconfig.json file, and includes a C# code example demonstrating how to selectively trigger updates on approved servers.

As the organization grows, managing updates across a large (and growing) server fleet can become increasingly complex. You may need more control than simply scheduling or automatically rolling out updates to every machine at once. Instead, you might want to approve each server individually and then trigger an update on only those selected machines.

This article outlines a scalable approach that grants you full control over which servers receive an update. Rather than rely on static update channels or scheduling, you’ll create a solution where each server checks a centrally hosted configuration file to determine whether it is allowed to update. If it is, the server then triggers the Advanced Installer Updater to check, download, and install the latest version.

2. Why a Granular Approach?

  • Large Number of Servers: When managing large number of servers (with more to come), grouping them into channels can quickly become unwieldy.
  • Fine-Grained Control: You want to decide which servers update and which remain on an older version—without scheduling or blanket rollouts.
  • Simplified Maintenance: Updating a single JSON file to reflect approved server IDs is easier than maintaining multiple channel configurations or scheduling times.

3. High-Level Architecture

  • Central Configuration File: Hosted on a server or cloud location (e.g., www.mywebsite.com/allow-server-update.json).
  • Local Server Check: Each server has an application or script that periodically (or on demand) checks the configuration file.
  • Approval List: If a server’s ID is in the list of allowed updates, it proceeds to compare its current version with the latest version in the JSON.
  • Trigger Updater: If the server is out of date and is approved, the local application triggers Advanced Installer’s Updater to check, download, and install updates. Check the How the Updater works article to see the steps of how an application is upgraded from one version to the next when using the Advanced Updater.

Here’s an example updateconfig.json file you might host on your server:

{
  "latestVersion": "1.1.0",
  "updateAllowedIds": [
    "server001",
    "server002",
    "server005"
  ]
}
      
  • latestVersion: The most recent version that should be installed by any server allowed to update.
  • updateAllowedIds: The list of server (or machine) IDs approved for the upgrade.

When you’re ready to allow a server to update, simply add its ID to this list. If you need to temporarily block updates, remove or omit that server’s ID.

4. Sample implementation in C#

Below is a simplified example of how you can implement this check in C#. Adapt it to your own language or framework as needed.

using System;
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json;

public class UpdateConfig
{
    public string LatestVersion { get; set; }
    public List <string> UpdateAllowedIds { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        // Example local settings
        string localId = "server001";     // Unique identifier for this machine
        string currentVersion = "1.0.0";  // Current version installed

        // URL to the update configuration file on your server
        string configUrl = "https://www.mywebsite.com/allow-server-update.json";

        try
        {
            using (WebClient webClient = new WebClient())
            {
                string json = webClient.DownloadString(configUrl);
                UpdateConfig config = JsonConvert.DeserializeObject<UpdateConfig>(json);

                // Check if this machine is in the allowed list
                if (config.UpdateAllowedIds.Contains(localId))
                {
                    // Compare version numbers (simple string check for demo purposes)
                    // In reality, parse version strings and compare properly
                    if (!currentVersion.Equals(config.LatestVersion, StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine($"Update available! Latest version is {config.LatestVersion}");
                        // Trigger your update process here
                        DownloadAndInstallUpdates();
                    }
                    else
                    {
                        // local version is already on the latest available
                        Console.WriteLine("Your version is up to date.");
                    }
                }
                else
                {
                    // local server is not on the list for updates
                    Console.WriteLine("No update available for this machine at this time.");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error checking for updates: " + ex.Message);
        }
    }

    static void DownloadAndInstallUpdates()
    {
        // 1. Just check silently if an update is available
        //    The return code from Updater.exe can be checked:
        //      0 => Update available
        //      -536870895 => No update
        //    For brevity, we’ll skip the actual process invocation here.

        // 2. If an update is available, download in the background:
        //    updater.exe /justdownload

        // 3. Once the application is about to exit or at another
        //    appropriate time, install the downloaded update:
        //    updater.exe /silent

        // Example placeholder
        Console.WriteLine("Simulating call to Updater: Checking, downloading, and installing updates...");
    }
}  

5. Behavior explanation

  • Fetching Configuration
    • The program downloads the JSON configuration from a central location (configUrl) and deserializes it into an UpdateConfig object.
  • Allowed List Check
    • It checks if the server’s unique ID is included in the updateAllowedIds list.
  • Version Comparisonn
    • If the server is allowed to update, it compares its current version against the latestVersion in the JSON.
  • Updater Integration
    • If the server is out of date, it runs a method (DownloadAndInstallUpdates) to launch the Advanced Installer Updater with specific command-line flags (/justcheck, /justdownload, etc.).

6. Advanced Installer Updater Workflow

  • Silent Check:updater.exe /justcheck
    • Returns 0 if an update is available.
    • Returns -536870895 if no update is available.
  • Download in Background:updater.exe /justdownload
    • Downloads the available update in the background.
  • Install on Exit (or at another suitable time)
    • For an interactive install: updater.exe /checknow.
    • Make sure the main application is not running (or prompt the user to close it) before installing the update to avoid file-in-use issues.

Handling Edge Cases

For servers not in the allowed list, the application simply continues to run without performing any updates. If the server is already on the latest version, it detects that it matches the “latestVersion” value and skips any update process. If there’s an issue downloading the JSON file or deserializing it, the application logs an error and can retry later.

Scaling the Approach

To add more servers, simply include new server IDs in the “updateAllowedIds” array within the updateconfig.json file. If you want to halt updates for a server, remove its ID from the JSON file. You can also build an internal tool or script that updates the JSON file whenever a server is approved for update, or even integrate it with a CI/CD pipeline.

Benefits of This Method

This approach grants granular control by letting you decide exactly which servers get updated and when. It offers scalable management, since maintaining a single JSON file is much simpler than handling multiple channels or scheduled tasks. It reduces risk by allowing you to roll out updates to a small subset of servers first, then gradually add more to the “updateAllowedIds” array if everything runs smoothly. Finally, it is easy to integrate into almost any language, relying on straightforward HTTP requests and JSON parsing.