diff --git a/MyApp.ServiceInterface/App/LogCommand.cs b/MyApp.ServiceInterface/App/LogCommand.cs new file mode 100644 index 0000000..d34a1f4 --- /dev/null +++ b/MyApp.ServiceInterface/App/LogCommand.cs @@ -0,0 +1,60 @@ +using System.Net.Mail; +using Microsoft.Extensions.Logging; +using MyApp.Data; +using ServiceStack; + +namespace MyApp.ServiceInterface.App; + +public class LogRequest +{ + public string Message { get; set; } +} + +public class LogCommand(ILogger log) : IAsyncCommand +{ + private static int count = 0; + + public Task ExecuteAsync(LogRequest request) + { + Interlocked.Increment(ref count); + log.LogInformation("Log {Count}: {Message}", count, request.Message); + return Task.CompletedTask; + } +} + +public class SendEmailCommand(ILogger log, SmtpConfig config) : IAsyncCommand +{ + private static int count = 0; + + public Task ExecuteAsync(SendEmail request) + { + Interlocked.Increment(ref count); + log.LogInformation("Sending {Count} email to {Email} with subject {Subject}", count, request.To, request.Subject); + + using var client = new SmtpClient(config.Host, config.Port); + client.Credentials = new System.Net.NetworkCredential(config.Username, config.Password); + client.EnableSsl = true; + + // If DevToEmail is set, send all emails to that address instead + var emailTo = config.DevToEmail != null + ? new MailAddress(config.DevToEmail) + : new MailAddress(request.To, request.ToName); + + var emailFrom = new MailAddress(config.FromEmail, config.FromName); + + var msg = new MailMessage(emailFrom, emailTo) + { + Subject = request.Subject, + Body = request.BodyHtml ?? request.BodyText, + IsBodyHtml = request.BodyHtml != null, + }; + + if (config.Bcc != null) + { + msg.Bcc.Add(new MailAddress(config.Bcc)); + } + + client.Send(msg); + return Task.CompletedTask; + } +} diff --git a/MyApp/Configure.BackgroundJobs.cs b/MyApp/Configure.BackgroundJobs.cs new file mode 100644 index 0000000..d47e88a --- /dev/null +++ b/MyApp/Configure.BackgroundJobs.cs @@ -0,0 +1,63 @@ +using MyApp.Data; +using MyApp.ServiceInterface.App; +using MyApp.ServiceModel; +using ServiceStack.Jobs; + +[assembly: HostingStartup(typeof(MyApp.ConfigureBackgroundJobs))] + +namespace MyApp; + +public class ConfigureBackgroundJobs : IHostingStartup +{ + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices(services => { + services.AddPlugin(new CommandsFeature()); + services.AddPlugin(new BackgroundsJobFeature()); + services.AddHostedService(); + }).ConfigureAppHost(afterAppHostInit:appHost => + { + var jobs = appHost.Resolve(); + + jobs.RecurringCommand("Every Minute", Schedule.EveryMinute, + new LogRequest { Message = "Hello from Recurring Command" }); + + jobs.RecurringCommand("Every 8 hours", Schedule.Interval(TimeSpan.FromHours(8)), + new SendEmail + { + To = "demis.bellot@gmail.com", + Subject = "Hi from recurring command", + BodyText = "Test email from a Scheduled Tasks recurring command" + }); + + jobs.RecurringApi("DbWrites Hourly", Schedule.Hourly, + new DbWrites { + PeriodicTasks = new PeriodicTasks { PeriodicFrequency = PeriodicFrequency.Hourly } + }); + + }); +} + +public class JobsHostedService(ILogger log, IBackgroundJobs jobs) : BackgroundService +{ + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await jobs.StartAsync(stoppingToken); + + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(3)); + var tick = 0; + var errors = 0; + while (!stoppingToken.IsCancellationRequested && await timer.WaitForNextTickAsync(stoppingToken)) + { + try + { + tick++; + await jobs.TickAsync(); + } + catch (Exception e) + { + log.LogError(e, "JOBS {Errors}/{Tick} Error in JobsHostedService: {Message}", + ++errors, tick, e.Message); + } + } + } +} \ No newline at end of file diff --git a/MyApp/Configure.Mq.cs b/MyApp/Configure.Mq.cs index 5ee6de4..8289e35 100644 --- a/MyApp/Configure.Mq.cs +++ b/MyApp/Configure.Mq.cs @@ -25,8 +25,9 @@ public void Configure(IWebHostBuilder builder) => builder services.AddSingleton(c => c.GetRequiredService().MessageFactory.CreateMessageProducer()); services.AddSingleton(); services.AddSingleton(); - services.AddPlugin(new CommandsFeature()); - services.AddHostedService(); + // services.AddPlugin(new CommandsFeature()); + // Use ServiceStack.Jobs Recurring Tasks instead + // services.AddHostedService(); }) .ConfigureAppHost(afterAppHostInit: appHost => { var mqService = appHost.Resolve(); diff --git a/MyApp/MyApp.csproj b/MyApp/MyApp.csproj index 9c4de3c..773f3c3 100644 --- a/MyApp/MyApp.csproj +++ b/MyApp/MyApp.csproj @@ -34,6 +34,7 @@ +