Skip to content

Instantly share code, notes, and snippets.

@cybergitt
Created July 30, 2025 17:20
Show Gist options
  • Select an option

  • Save cybergitt/9b38acd1ff0fd1fcda15326601aa0b36 to your computer and use it in GitHub Desktop.

Select an option

Save cybergitt/9b38acd1ff0fd1fcda15326601aa0b36 to your computer and use it in GitHub Desktop.
// 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