Polling in Software Systems

 

Polling in Software Systems

Polling is a technique where a system repeatedly checks for changes or new data at regular intervals. It is often used when event-driven notifications (e.g., WebSockets, SQL Server notifications) are not available or feasible.


1. Types of Polling

a) Regular Polling (Fixed Interval)

  • The system checks for updates at a fixed time interval (e.g., every 10 seconds).
  • Simple to implement but can cause unnecessary load if updates are infrequent.

🔹 Example:
A background service in .NET Core checking for new database records every minute.

public class PollingService : BackgroundService
{
    private readonly ILogger<PollingService> _logger;

    public PollingService(ILogger<PollingService> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Checking for updates...");
            CheckForUpdates();  // Replace with actual data check logic
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }
    }

    private void CheckForUpdates()
    {
        // Query the database or API to check for changes
        _logger.LogInformation("Polling database...");
    }
}

Pros:

  • Simple to implement.
  • No external dependencies.

Cons:

  • Wastes resources when there are no changes.
  • Database or API load increases with shorter intervals.

b) Adaptive Polling (Backoff Strategy)

  • Dynamically adjusts polling frequency based on system activity.
  • If no changes occur, polling slows down (e.g., from 5 sec → 10 sec → 30 sec).

🔹 Example:
If the last 5 polls detected no changes, increase the delay.

public class AdaptivePollingService : BackgroundService
{
    private readonly ILogger<AdaptivePollingService> _logger;
    private int _pollingInterval = 5000;  // Start with 5 seconds
    private int _missedUpdates = 0;

    public AdaptivePollingService(ILogger<AdaptivePollingService> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            bool dataChanged = CheckForUpdates();

            if (dataChanged)
            {
                _pollingInterval = 5000;  // Reset to 5 seconds
                _missedUpdates = 0;
            }
            else
            {
                _missedUpdates++;
                if (_missedUpdates >= 5) _pollingInterval = Math.Min(_pollingInterval * 2, 60000); // Max 60 sec
            }

            await Task.Delay(_pollingInterval, stoppingToken);
        }
    }

    private bool CheckForUpdates()
    {
        // Simulate checking database for updates
        _logger.LogInformation("Checking for updates...");
        return new Random().Next(0, 10) < 2;  // Simulate a 20% chance of change
    }
}

Pros:

  • Reduces unnecessary database queries.
  • Improves performance & efficiency.

Cons:

  • Delayed responses if updates occur after a long backoff.
  • More complex than fixed interval polling.

c) Long Polling

  • The client sends a request to the server and waits until a change occurs.
  • If the server detects a change, it immediately responds.
  • If no change occurs within a timeout (e.g., 30 sec), the server responds empty, and the client retries.

🔹 Example:
Long polling to get real-time notifications from a REST API.

[HttpGet("long-polling")]
public async Task<IActionResult> LongPolling(CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        if (CheckForUpdates())  // If data changed, return response
            return Ok(new { message = "New data available!" });

        await Task.Delay(5000, cancellationToken);  // Wait before checking again
    }
    return NoContent();
}

Pros:

  • Real-time updates without constant requests.
  • Reduces unnecessary polling when no updates exist.

Cons:

  • Requires holding HTTP connections, which can be inefficient for large-scale applications.

2. Polling in Different Scenarios


3. Polling in .NET Core with Caching

🔹 Example: Polling SQL Server and caching the results in MemoryCache.

public class DatabasePollingService : BackgroundService
{
    private readonly IMemoryCache _cache;
    private readonly string _connectionString;
    private DateTime _lastUpdated = DateTime.MinValue;

    public DatabasePollingService(IMemoryCache cache, IConfiguration config)
    {
        _cache = cache;
        _connectionString = config.GetConnectionString("DefaultConnection");
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            await RefreshCacheIfNeeded();
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }
    }

    private async Task RefreshCacheIfNeeded()
    {
        using var connection = new SqlConnection(_connectionString);
        using var command = new SqlCommand("SELECT MAX(LastModified) FROM Products", connection);
        connection.Open();
        
        var lastModified = (DateTime?)await command.ExecuteScalarAsync();
        if (lastModified > _lastUpdated)
        {
            _lastUpdated = lastModified ?? DateTime.MinValue;
            _cache.Remove("ProductsCache");  // Clear cache
        }
    }
}

4. Polling vs Event-Driven Alternatives


5. When to Use Polling?

✔️ When event-driven options are not available.
✔️ When the data doesn’t change often (adaptive polling).
✔️ When you need simple implementation without extra dependencies.

❌ Avoid polling when real-time performance is required.
❌ Avoid polling when server load is a concern (use SQL Dependency or SignalR instead).


Conclusion

  • Fixed polling is simple but wastes resources.
  • Adaptive polling improves efficiency by dynamically adjusting the interval.
  • Long polling provides real-time-like behavior without excessive requests.
  • Consider event-driven solutions like SQL Dependency, WebSockets, or message queues for better performance.

Comments

Popular posts from this blog

Maxpooling vs minpooling vs average pooling

Generative AI - Prompting with purpose: The RACE framework for data analysis

Best Practices for Storing and Loading JSON Objects from a Large SQL Server Table Using .NET Core