Created
July 30, 2025 17:20
-
-
Save cybergitt/9b38acd1ff0fd1fcda15326601aa0b36 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Worker Service Program.cs | |
| using Microsoft.Extensions.DependencyInjection; | |
| using Microsoft.Extensions.Hosting; | |
| using Microsoft.Extensions.Logging; | |
| using FluentValidation; | |
| using FluentValidation.Results; | |
| using System; | |
| using System.IO; | |
| using System.Linq; | |
| using System.Collections.Generic; | |
| using System.Threading; | |
| using System.Threading.Tasks; | |
| var host = Host.CreateDefaultBuilder(args) | |
| .ConfigureServices((context, services) => | |
| { | |
| services.AddHostedService<FileWorker>(); | |
| services.AddSingleton<IValidator<FileRequest>, FileRequestValidator>(); | |
| services.AddSingleton<FileProcessor>(); | |
| }) | |
| .Build(); | |
| await host.RunAsync(); | |
| public class FileWorker : BackgroundService | |
| { | |
| private readonly ILogger<FileWorker> _logger; | |
| private readonly FileProcessor _processor; | |
| private readonly IValidator<FileRequest> _validator; | |
| public FileWorker(ILogger<FileWorker> logger, FileProcessor processor, IValidator<FileRequest> validator) | |
| { | |
| _logger = logger; | |
| _processor = processor; | |
| _validator = validator; | |
| } | |
| protected override async Task ExecuteAsync(CancellationToken stoppingToken) | |
| { | |
| while (!stoppingToken.IsCancellationRequested) | |
| { | |
| var request = new FileRequest { Path = "data.txt" }; | |
| ValidationResult validation = _validator.Validate(request); | |
| if (!validation.IsValid) | |
| { | |
| foreach (var error in validation.Errors) | |
| { | |
| _logger.LogError("[VALIDATION] {Property}: {Message}", error.PropertyName, error.ErrorMessage); | |
| } | |
| await Task.Delay(10000, stoppingToken); | |
| continue; | |
| } | |
| var result = await _processor.ProcessFileAsync(request); | |
| if (result.IsSuccess) | |
| { | |
| _logger.LogInformation("File processed. Content:\n{0}", result.Value); | |
| } | |
| else | |
| { | |
| foreach (var error in result.Errors) | |
| { | |
| _logger.LogError("[PROCESSING ERROR] {0}: {1}", error.Code, error.Message); | |
| } | |
| } | |
| await Task.Delay(30000, stoppingToken); // wait 30 sec before retry | |
| } | |
| } | |
| } | |
| public class FileRequest | |
| { | |
| public string Path { get; set; } = string.Empty; | |
| } | |
| public class FileRequestValidator : AbstractValidator<FileRequest> | |
| { | |
| public FileRequestValidator() | |
| { | |
| RuleFor(x => x.Path) | |
| .NotEmpty().WithMessage("Path is required.") | |
| .Must(File.Exists).WithMessage("File must exist."); | |
| } | |
| } | |
| public class FileProcessor | |
| { | |
| public async Task<Result<string>> ProcessFileAsync(FileRequest request) | |
| { | |
| try | |
| { | |
| var content = await File.ReadAllTextAsync(request.Path); | |
| return Result<string>.Success(content); | |
| } | |
| catch (Exception ex) | |
| { | |
| return Result<string>.Failure(new Error("FileReadError", ex.Message)); | |
| } | |
| } | |
| } | |
| public class Result<T> | |
| { | |
| public bool IsSuccess { get; } | |
| public T? Value { get; } | |
| public List<Error> Errors { get; } | |
| public static Result<T> Success(T value) => new(true, value, new List<Error>()); | |
| public static Result<T> Failure(params Error[] errors) => new(false, default, errors.ToList()); | |
| private Result(bool isSuccess, T? value, List<Error> errors) | |
| { | |
| IsSuccess = isSuccess; | |
| Value = value; | |
| Errors = errors; | |
| } | |
| } | |
| public record Error(string Code, string Message); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment