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!
