Batch İşler İçin Konsol Uygulaması | C#

Merhaba, batch olarak çalışan işler için ayrı ayrı konsol uygulamaları yazıyordum. Daha sonra aklıma şöyle bir fikir geldi: Hepsi için tek bir konsol uygulaması yazayım, iş geldikçe yeni görevleri ekleyeyim.

Elbette bu “en doğru yöntem” demek değil — ama uygulanabilir, pratik bir yaklaşım. Bu yapıda, uygulama her saat bir kez çalışıyor ve o saate atanmış işleri Jobs.xml dosyasından okuyup sırayla yürütüyor.

Jobs.xml – İş Tanımlama Dosyası

<?xml version="1.0" encoding="utf-8" ?>
<Jobs>
  <Job FirmaKodu="02" Hour="20" Class="ConsoleBatchIsler.SiparisMailJob" />
  <Job FirmaKodu="02" Hour="10" Class="ConsoleBatchIsler.AmazonEbayStokGuncellemeJob" />
  <Job FirmaKodu="02" Hour="11" Class="ConsoleBatchIsler.AmazonEbayStokGuncellemeJob" />
  <Job FirmaKodu="02" Hour="12" Class="ConsoleBatchIsler.AmazonEbayStokGuncellemeJob" />
  <!-- Diğer saatler... -->
</Jobs>

Her iş için FirmaKodu, çalışacağı saat (Hour) ve sınıf adı (Class) belirtiliyor. Konsol uygulaması, sistem saatiyle eşleşen job’ları bulup yürütüyor.

Program.cs

public static class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine($"Hourly Job Scheduler - {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
        Console.WriteLine(new string('=', 50));

        try
        {
            JobScheduler scheduler = new();
            scheduler.LoadJobs("Jobs.xml");
            await scheduler.RunCurrentHourJobsAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Kritik hata: {ex.Message}");
            await File.AppendAllTextAsync("critical_errors.log",
                $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}: {ex}\n{new string('=', 80)}\n");
            Environment.Exit(1);
        }

        Console.WriteLine("İşlem tamamlandı.");

        // Debug için
        if (args.Length > 0 && args[0] == "--debug")
        {
            Console.WriteLine("Debug modu - Enter tuşuna basın...");
            Console.ReadLine();
        }
    }
}

JobScheduler Sınıfı

public class JobScheduler
{
    private readonly List<(string FirmaKodu, int Hour, string ClassName)> _jobs = [];

    public void LoadJobs(string xmlPath)
    {
        XDocument doc = XDocument.Load(xmlPath);
        foreach (XElement jobElement in doc.Descendants("Job"))
        {
            string firmaKodu = jobElement.Attribute("FirmaKodu")!.Value;
            int hour = int.Parse(jobElement.Attribute("Hour")!.Value);
            string className = jobElement.Attribute("Class")!.Value;
            _jobs.Add((firmaKodu, hour, className));
        }
    }

    public async Task RunCurrentHourJobsAsync()
    {
        int currentHour = DateTime.Now.Hour;
        foreach ((string firmaKodu, int hour, string className) in _jobs)
        {
            if (hour == currentHour)
            {
                Type type = Assembly.GetExecutingAssembly().GetType(className!, throwOnError: true)!;
                IJob job = (IJob)Activator.CreateInstance(type!)!;
                Console.WriteLine($"{DateTime.Now}: {className} çalışıyor...");
                await job.RunAsync(firmaKodu);
            }
        }
    }
}

IJob Arayüzü

public interface IJob
{
    Task RunAsync(string FirmaKodu);
}

Örnek Job: Sipariş Maili Gönderme

public class SiparisMailJob : IJob
{
    public async Task RunAsync(string FirmaKodu)
    {
        List<SiparisBelgeBaslik> lst;
        List<SiparisBelgeSatir> lstSatir;
        Console.WriteLine("Müşterilere sipariş maili gönderiliyor...");

        var param = new { FirmaKodu };
        string sp = "PRC_GETIRGUNUNASBELGELERI";

        using (SrvVeritabaniIslemleri db = new())
        {
            lst = await db.GetirVeriAsync<SiparisBelgeBaslik>(sp, param);
            if (lst != null && lst.Count != 0)
            {
                foreach (var itemBaslik in lst)
                {
                    var param2 = new
                    {
                        FirmaKodu,
                        itemBaslik.ReservationDocType,
                        itemBaslik.ReservationDocNum
                    };
                    sp = "PRC_GETIRBELGESATIRLAR";
                    lstSatir = await db.GetirVeriAsync<SiparisBelgeSatir>(sp, param2);

                    if (lstSatir != null && lstSatir.Count != 0)
                    {
                        byte[] b = ExcelIslemleri.OlusturExcel(lstSatir, "Order_Notification");
                        EPostaIslemleri.EPostaYolla(
                            [itemBaslik.EMail],
                            ["zamkinos@gmail.com"],
                            "Geachte heer/mevrouw,<br /><br />In de bijlage vindt u de orderbevestiging.<br /><br />Met vriendelijke groet,<br />Zamkinos Bilişim Danışmanlık",
                            "Order-Reservation Notification",
                            [b],
                            ["Order_Notification_" + DateTime.Now.ToString("yyyyMMdd") + ".xlsx"]
                        );
                    }
                }
            }
        }

        Console.WriteLine("Bitti.");
    }
}

Amazon / eBay Stok Güncelleme Örneği

public class AmazonEbayStokGuncellemeJob : IJob
{
    public async Task RunAsync(string FirmaKodu)
    {
        // Amazon / eBay stok güncelleme işlemleri burada
        await new AmazonEbayIslemleri().RunAsync(FirmaKodu);
    }
}

Zamanla proje büyüdükçe okunabilirlik azalabilir, o durumda ayrı konsollar tercih edilebilir. Ama bu yaklaşım, küçük/orta ölçekli otomasyonlar için gayet pratik bir çözüm.

Selamlar!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top