Offloader 1.0.6

There is a newer version of this package available.
See the version list below for details.
dotnet add package Offloader --version 1.0.6
NuGet\Install-Package Offloader -Version 1.0.6
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Offloader" Version="1.0.6" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Offloader --version 1.0.6
#r "nuget: Offloader, 1.0.6"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Offloader as a Cake Addin
#addin nuget:?package=Offloader&version=1.0.6

// Install Offloader as a Cake Tool
#tool nuget:?package=Offloader&version=1.0.6

Offloader

NuGet license

A convenient way to unload some heavy work to background service from your main requests.

Install as NuGet package:

Install-Package Offloader
<PackageReference Include="Offloader" Version="1.0.*" />

Configurables

Processor func or service

// func
services.AddOffload<OffloadItemType>(x => x.UseItemProcessor(serviceProvider, item, ct) => ...);

// service, must implement IOffloadItemProcessor
services.AddOffload<OffloadItemType, YourServiceProcessorType>();

Degree of Parallelism

// default value is 1
x.UseDegreeOfParallelism(5)

Custom error logging

x.UseErrorLogger((logger, item, exception) => logger.LogError(ex, "Log in any format {WithValues}", item.Value))

Samples

Full samples can be found in Examples directory.

Simplest sample

var builder = WebApplication.CreateBuilder(args);

// ...

builder.Services.AddOffload<OffloadItemType>(x => x.UseItemProcessor((_, item, _) => 
    {
        Console.WriteLine($"Processing item with value {item.State}");
        return Task.CompletedTask;
    })
});

// ...
    
var app = builder.Build();

// use offloader in your handlers or in your controllers
app.MapPost(
    "/my-heavy-endpoint", 
    (string itemValue, IOffloader<OffloadItemType> x) => x.OffloadAsync(new OffloadItemType(itemState)));

public record OffloadItemType(string State);

Sample with inline processor function

var builder = WebApplication.CreateBuilder(args);

// ...

// register offloader function for specified Type (in this sample it's OffloadItemType)
builder.Services.AddOffload<OffloadItemType>(options =>
{
    options
        // specify processor func (required)
        .UseItemProcessor(async (provider, item, ct) =>
        {
            // request any registered service (scoped should work fine)
            // e.g. var http = provider.GetRequiredService<IHttpClientFactory>();

            // process item one by one
            Console.WriteLine($"Processing item with value {item.Value}");
            await Task.Delay(2000, ct);
        })
        
        // specify error handler, e.g. logger (optional)
        .UseErrorLogger((logger, item, ex) => logger.LogError(ex, "Log in any format {WithValues}", item.Value))
        
        // specify degree of parallelism (optional, default is 1)
        .UseDegreeOfParallelism(2);
});

// ...
    
var app = builder.Build();

// use offloader in your handlers or in your controllers
app.MapPost(
    "/my-heavy-endpoint", 
    async (string itemValue, IOffloader<OffloadItemType> offloader) =>
    {
        // do some work before returning response to the client
        
        // offload heavy work to background service
        await offloader.OffloadAsync(new OffloadItemType(itemValue)); 

        return Results.Created();
    });

public record OffloadItemType(string Value);

Sample with processor as a service class

var builder = WebApplication.CreateBuilder(args);

// ...

// register offloader with processing service for certain offload type (in this sample it's ItemProcessorType and OffloadItemType)
builder.Services.AddOffload<OffloadItemType, OffloadItemProcessorType>(options =>
{
    options
        // specify error handler, e.g. logger (optional)
        .UseErrorLogger((logger, item, ex) => logger.LogError(ex, "Log in any format {WithValues}", item.Value))
        
        // specify degree of parallelism (optional, default is 1)
        .UseDegreeOfParallelism(2);
});

// ...
    
var app = builder.Build();

// use offloader in your handlers or in your controllers
app.MapPost(
    "/my-heavy-endpoint", 
    async (string name, string avatarUrl, IOffloader<OffloadItemType> offloader) =>
    {
        // do some work before returning response to the client
        
        // offload heavy work to background service~~~~
        await offloader.OffloadAsync(new OffloadItemType(itemValue)); 

        return Results.Created();
    });

// Create a processor that implements IOffloadItemProcessor<OffloadItemType>
public class OffloadItemProcessorType : IOffloadItemProcessor<OffloadItemType>
{
    // Inject any required service, for each item separate scope is created
    private readonly IHttpClientFactory _http;
    private static int _counter;

    public AvatarOffloadItemProcessor(IHttpClientFactory http) => _http = http;

    // Process item here
    public async Task ProcessAsync(ProcessNewAvatar item, CancellationToken ct)
    {
        // process items~~~~
        Interlocked.Increment(ref _counter);
        Console.WriteLine($"{_counter} | Processing user {item.Name} with avatar {item.AvatarUrl}");
        await Task.Delay(Random.Shared.Next(0, 4000), ct);
        Interlocked.Decrement(ref _counter);
        Console.WriteLine($"{_counter}");
    }
}

public record OffloadItemType(string Value);
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.7 76 5/16/2024
1.0.6 38 5/2/2024
1.0.5 76 5/1/2024
1.0.4 73 5/1/2024
1.0.3 80 4/30/2024
1.0.2 77 4/30/2024
1.0.1 91 4/30/2024
1.0.0 81 4/30/2024