C# Academy · Ders

Düzenli Görevler ve Zamanlayıcılar

PeriodicTimer ve System.Threading.Timer ile yinelenen işleri zamanlayın, iptali sorunsuz şekilde yönetin.

3. ders / 412 adım

Düzenli Görevler ve Zamanlayıcılar, CoddyKit'te ücretsiz bir C# Academy dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, C# Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. C# Academy kursu toplamda 4 dersten oluşur.

Yinelenen İşleri Zamanlama

Birçok arka plan hizmetinin sabit bir zamanlamayla, örneğin her 5 dakikada, her saat veya her gün çalışması gerekir. .NET bunun için çeşitli mekanizmalar sağlar: PeriodicTimer (modern), System.Threading.Timer (klasik) ve Quartz.NET (cron tabanlı).

PeriodicTimer: Modern Seçim

PeriodicTimer (.NET 6 ile tanıtılmıştır), async yöntemlerde kullanılmak üzere tasarlanmıştır. Geri çağırmalar olmadan tam zamanında tetiklenir ve iptal işlemiyle sorunsuz şekilde tümleşir.

public class MetricsCollectorService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));

        while (await timer.WaitForNextTickAsync(ct))
        {
            // Runs every 60 seconds
            await CollectMetricsAsync(ct);
        }
        // Loop exits cleanly when ct is cancelled
    }
}

PeriodicTimer ve Task.Delay Döngüsü

PeriodicTimer, Task.Delay döngüsünden daha iyidir: başlangıç zamanı + işleme süresi yerine başlangıç zamanından itibaren sabit aralıklarla tetiklenir ve çok sayıda yineleme boyunca zaman kaymasını önler.

// Task.Delay loop — drifts! (interval = delay + work time)
while (!ct.IsCancellationRequested)
{
    await DoWorkAsync(ct); // takes 2 seconds
    await Task.Delay(5000, ct); // actual period: 7 seconds
}

// PeriodicTimer — no drift
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5));
while (await timer.WaitForNextTickAsync(ct))
{
    await DoWorkAsync(ct); // period is still 5 seconds from start
}

System.Threading.Timer

System.Threading.Timer, geri çağırma kullanan klasik bir iş parçacığı havuzu zamanlayıcısıdır. Hem yinelenen hem de tek seferlik kipleri destekler. Dikkatli olun: geri çağırma, async desteği olmayan bir iş parçacığı havuzunda çalışır.

public class LegacyTimerService : BackgroundService, IDisposable
{
    private Timer? _timer;

    protected override Task ExecuteAsync(CancellationToken ct)
    {
        // Fire immediately then every 10 seconds
        _timer = new Timer(DoWork, null,
            dueTime:  TimeSpan.Zero,
            period:   TimeSpan.FromSeconds(10));
        return Task.CompletedTask;
    }

    private void DoWork(object? state)
    {
        // Runs on thread pool — avoid async void here
        Console.WriteLine($"Timer fired: {DateTime.UtcNow}");
    }

    public override void Dispose() { _timer?.Dispose(); base.Dispose(); }
}

Tek Seferlik Gecikmeli Çalıştırma

Tek seferlik gecikmeli çalıştırma için PeriodicTimer ile tek bir tik kullanın veya CancellationTokenSource.CancelAfter ile Task.Delay yöntemlerini birlikte kullanın.

// Run once after a delay
public async Task ScheduleOnceAsync(TimeSpan delay, Func<Task> action, CancellationToken ct)
{
    await Task.Delay(delay, ct);
    await action();
}

// Or with CancellationToken:
var cts = new CancellationTokenSource(TimeSpan.FromHours(1));
try
{
    await Task.Delay(Timeout.Infinite, cts.Token);
}
catch (OperationCanceledException)
{
    await RunScheduledJobAsync();
}

PeriodicTimer ile Hata İşleme

Tek bir hatanın sonraki döngüde zamanlayıcının yeniden tik atmasını durdurmaması için her tikteki işi her zaman try/catch içine alın.

protected override async Task ExecuteAsync(CancellationToken ct)
{
    using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));

    while (await timer.WaitForNextTickAsync(ct))
    {
        try
        {
            await SyncInventoryAsync(ct);
        }
        catch (Exception ex)
        {
            // Log but don't crash — next tick will retry
            _logger.LogError(ex, "Inventory sync failed");
        }
    }
}

Saat Sınırlarına Hizalama

Belirli saatlerde çalıştırmak, örneğin her saat başında çalıştırmak için zamanlayıcıyı başlatmadan önce bir sonraki sınıra kadar olan başlangıç gecikmesini hesaplayın.

protected override async Task ExecuteAsync(CancellationToken ct)
{
    // Wait until the next full hour
    var now = DateTime.UtcNow;
    var nextHour = now.Date.AddHours(now.Hour + 1);
    var initialDelay = nextHour - now;

    await Task.Delay(initialDelay, ct);

    // Then tick every hour exactly
    using var timer = new PeriodicTimer(TimeSpan.FromHours(1));

    await RunJobAsync(ct); // run at the first tick
    while (await timer.WaitForNextTickAsync(ct))
        await RunJobAsync(ct);
}

Eşzamanlı Tikleri Önleme

İşin bir zamanlayıcı döneminden uzun sürmesi mümkünse SemaphoreSlim ile eşzamanlı çalışmaya karşı koruma sağlayın veya iş hâlâ sürüyorsa tiki atlayın.

private readonly SemaphoreSlim _lock = new(1, 1);

protected override async Task ExecuteAsync(CancellationToken ct)
{
    using var timer = new PeriodicTimer(TimeSpan.FromSeconds(30));

    while (await timer.WaitForNextTickAsync(ct))
    {
        // Skip if previous tick is still running
        if (!await _lock.WaitAsync(0, ct))
        {
            _logger.LogWarning("Skipping tick — previous still running");
            continue;
        }
        try { await DoWorkAsync(ct); }
        finally { _lock.Release(); }
    }
}

Dağıtık Hizmetler için Rastgele Gecikme

Bir hizmetin birden çok örneği aynı anda başladığında, başlangıç gecikmesine rastgele bir gecikme eklemek paylaşılan kaynaklarda oluşan yoğun istek sorunlarını önler.

protected override async Task ExecuteAsync(CancellationToken ct)
{
    // Add jitter: 0-5 seconds random delay on startup
    var jitter = TimeSpan.FromSeconds(Random.Shared.NextDouble() * 5);
    await Task.Delay(jitter, ct);

    using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
    while (await timer.WaitForNextTickAsync(ct))
        await RunJobAsync(ct);
}

Gerçek Dünya: Önbellek Yenileme Hizmeti

Dağıtık bir önbelleği her 10 dakikada bir yenileyen, rastgele gecikme ve hata kurtarma özelliklerine sahip dönemsel bir hizmet.

public class CacheRefreshService : BackgroundService
{
    private readonly IServiceScopeFactory _factory;
    private readonly ILogger<CacheRefreshService> _log;

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        // Spread startups across instances
        await Task.Delay(TimeSpan.FromSeconds(Random.Shared.Next(0, 30)), ct);

        using var timer = new PeriodicTimer(TimeSpan.FromMinutes(10));
        while (await timer.WaitForNextTickAsync(ct))
        {
            try
            {
                using var scope = _factory.CreateScope();
                var cache = scope.ServiceProvider.GetRequiredService<ICacheService>();
                await cache.RefreshAllAsync(ct);
                _log.LogInformation("Cache refreshed at {Time}", DateTime.UtcNow);
            }
            catch (Exception ex) { _log.LogError(ex, "Cache refresh failed"); }
        }
    }
}

Kısa Kontrol

Yinelenen görevlerde Task.Delay döngüsü yerine PeriodicTimer neden tercih edilir?

Özet: Dönemsel Görevler ve Zamanlayıcılar

Temel çıkarımlar:

  • PeriodicTimer: async, iptali dikkate alır, zaman kayması oluşturmaz — modern seçimdir
  • System.Threading.Timer: geri çağırma tabanlıdır, eski kodlarla tümleştirme için uygundur
  • Hataların zamanlayıcıyı durdurmaması için her tikteki işi try/catch içine alın
  • Dağıtık örneklerde yoğun istek sorununu önlemek için rastgele gecikme ekleyin
  • Önceki tik hâlâ çalışıyorsa tiki atlamak için SemaphoreSlim kullanın
  • Tikleri saat sınırlarıyla hizalamak için başlangıç gecikmesini hesaplayın
Başlamak ücretsiz

Yapay zeka eğitmeniyle C# öğren — ücretsiz

Tarayıcında gerçek kod yaz ve çalıştır, 7/24 yapay zeka eğitmeninden anında yardım al; web'de ya da uygulamada kaldığın yerden devam et.

Kurslar
93
Dersler
346

Sıkça Sorulan Sorular

“Düzenli Görevler ve Zamanlayıcılar” dersi ücretsiz mi?

Evet — “Düzenli Görevler ve Zamanlayıcılar” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve C# Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. C# Academy kursu toplamda 4 dersten oluşur.

“Düzenli Görevler ve Zamanlayıcılar” dersinde ne öğreneceğim?

PeriodicTimer ve System.Threading.Timer ile yinelenen işleri zamanlayın, iptali sorunsuz şekilde yönetin. C# Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

C# Academy öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te C# Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.

“Düzenli Görevler ve Zamanlayıcılar” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu C# Academy dersinde kod yazıp çalıştırabilir miyim?

Evet. Her C# Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. IHostedService ve BackgroundService
  2. Worker Service Projeleri
  3. Düzenli Görevler ve Zamanlayıcılar
  4. Quartz.NET Zamanlanmış İşleri
← C# Academy Sayfasına Dön