Skip to content

Runtime Checking

Runtime update checking allows your application to check for updates during execution, either in the foreground or background.

Foreground Checking

Foreground checking is synchronous and blocks until the check completes:

zig
const std = @import("std");
const updater = @import("updater");

pub fn checkUpdates(allocator: std.mem.Allocator) !void {
    const result = try updater.checkForUpdates(allocator, .{
        .enabled = true,
        .provider = updater.providers.github,
        .owner = "username",
        .repo = "myapp",
        .current_version = "1.0.0",
        .timeout_ms = 5000,
    });

    if (result.has_update) {
        std.debug.print("Update available: {s}\n", .{result.latest_version.?});
    }
}

Background Checking

Background checking runs in a separate thread and periodically checks for updates:

zig
const std = @import("std");
const updater = @import("updater");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Start background checker
    const checker = try updater.startBackgroundChecker(allocator, .{
        .enabled = true,
        .background = true,
        .interval_seconds = 3600,  // Check every hour
        .provider = updater.providers.github,
        .owner = "username",
        .repo = "myapp",
        .current_version = "1.0.0",
        .on_update = onUpdateFound,
    });
    defer checker.stop();

    // Your application runs here...
    // The background checker will call onUpdateFound when an update is found
}

fn onUpdateFound(result: updater.UpdateResult) void {
    std.debug.print("Update found: {s}\n", .{result.latest_version.?});
}

Full Configuration

The UpdateConfig struct provides complete control:

zig
const config = updater.UpdateConfig{
    // Core settings
    .enabled = true,              // Enable/disable checking
    .background = false,          // Run in background thread
    .interval_seconds = 86400,    // Check interval (background mode)
    .timeout_ms = 10000,          // HTTP timeout

    // Repository information
    .provider = updater.providers.github,
    .owner = "username",
    .repo = "myproject",
    .current_version = "1.0.0",

    // Optional settings
    .comparator = updater.version.semantic,  // Version comparison
    .include_prereleases = false,            // Include prerelease versions
    .user_agent = "myapp/1.0",              // Custom User-Agent
    .on_update = myCallback,                 // Callback for background mode
};

Result Handling

The UpdateResult struct contains comprehensive information:

zig
pub const UpdateResult = struct {
    has_update: bool,           // Whether an update is available
    skipped: bool,              // Whether the check was skipped
    skip_reason: SkipReason,    // Reason for skipping
    current_version: []const u8,
    latest_version: ?[]const u8,
    release_url: ?[]const u8,
    release_info: ?ReleaseInfo, // Full release information
    error_message: ?[]const u8, // Error details if failed
};

Skip Reasons

zig
pub const SkipReason = enum {
    none,              // Not skipped
    globally_disabled, // ZIG_UPDATE_CHECK_DISABLE is set
    config_disabled,   // enabled = false in config
    ci_environment,    // Running in CI
    network_error,     // Network request failed
    rate_limited,      // API rate limit exceeded
    provider_error,    // Provider returned an error
};

Error Handling

Runtime checks are designed to be resilient:

zig
const result = updater.checkForUpdates(allocator, config) catch |err| {
    switch (err) {
        error.GloballyDisabled => {
            // User has opted out
            return;
        },
        error.NetworkError, error.Timeout => {
            // Network issue - log and continue
            std.log.warn("Update check failed: {}", .{err});
            return;
        },
        else => {
            // Unexpected error
            std.log.err("Unexpected error: {}", .{err});
            return;
        },
    }
};

Best Practices

1. Respect User Preferences

Always check if update checking is globally disabled:

zig
if (updater.isGloballyDisabled()) {
    return;  // User has opted out
}

2. Use Appropriate Timeouts

Set reasonable timeouts to avoid hanging:

zig
.timeout_ms = 5000,  // 5 seconds is usually sufficient

3. Handle Failures Gracefully

Never let update check failures crash your application:

zig
const result = updater.checkForUpdates(allocator, config) catch {
    // Log and continue
    return;
};

4. Background Check Intervals

Use reasonable intervals for background checks:

zig
.interval_seconds = 86400,  // Once per day is usually sufficient

5. Inform Users

Let users know when checking and what you do with the data:

zig
std.debug.print("Checking for updates...\n", .{});

Next Steps

Released under the MIT License.