-
Notifications
You must be signed in to change notification settings - Fork 2
Examples
Meyn edited this page Dec 15, 2025
·
1 revision
Comprehensive examples demonstrating real-world usage of
- Basic Examples
- File Operations
- HTTP Requests
- Database Operations
- Game Development
- Progress Tracking
- Advanced Patterns
using Shard.Requests;
// Minimal setup - auto-starts and uses main handler
var request = new OwnRequest(async token =>
{
await Task.Delay(1000, token);
Console.WriteLine("Task completed!");
return true; // Success
});
// Wait for completion
await request.Task;var request = new OwnRequest(async token =>
{
// Simulate operation that might fail
if (Random.Shared.Next(0, 3) == 0)
return false; // Trigger retry
await Task.Delay(500, token);
return true;
}, new RequestOptions<VoidStruct, VoidStruct>
{
Priority = RequestPriority.High,
NumberOfAttempts = 5,
DelayBetweenAttempts = TimeSpan.FromSeconds(2),
RequestStarted = req => Console.WriteLine("Starting..."),
RequestCompleted = (req, _) => Console.WriteLine("Success!"),
RequestFailed = (req, _) => Console.WriteLine("Failed after all retries"),
RequestExceptionOccurred = (req, ex) => Console.WriteLine($"Error: {ex.Message}")
});
await request.Task;var request = new OwnRequest(async token =>
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(100, token);
Console.WriteLine($"Step {i + 1}/10");
}
return true;
}, new() { AutoStart = false }); // Don't auto-start
// Start manually
Console.WriteLine("Press Enter to start...");
Console.ReadLine();
request.Start();
// Pause
Console.WriteLine("Press Enter to pause...");
Console.ReadLine();
request.Pause();
// Resume
Console.WriteLine("Press Enter to resume...");
Console.ReadLine();
request.Start();
await request.Task;using Shard.Requests;
using System.Net.Http;
public class FileDownloader
{
private readonly HttpClient _client = new();
private readonly ParallelRequestHandler _handler = new()
{
StaticDegreeOfParallelism = 5 // 5 concurrent downloads
};
public async Task DownloadFilesAsync(Dictionary<string, string> urlToPath)
{
var requests = urlToPath.Select(kvp => new OwnRequest(async token =>
{
try
{
var response = await _client.GetAsync(kvp.Key, token);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsByteArrayAsync(token);
await File.WriteAllBytesAsync(kvp.Value, content, token);
Console.WriteLine($"Downloaded: {kvp.Key}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Failed {kvp.Key}: {ex.Message}");
return false; // Retry
}
}, new()
{
Handler = _handler,
NumberOfAttempts = 3,
DelayBetweenAttempts = TimeSpan.FromSeconds(5)
})).ToList();
// Wait for all downloads
await _handler.Task;
}
}
// Usage:
var downloader = new FileDownloader();
await downloader.DownloadFilesAsync(new Dictionary<string, string>
{
["https://example.com/file1.zip"] = "file1.zip",
["https://example.com/file2.zip"] = "file2.zip",
["https://example.com/file3.zip"] = "file3.zip"
});public class DirectoryScanner
{
public async Task<List<string>> FindFilesAsync(
string rootPath,
string pattern,
IProgress<float> progress)
{
var results = new List<string>();
var directories = Directory.GetDirectories(rootPath, "*", SearchOption.AllDirectories);
int processed = 0;
var request = new OwnRequest(async token =>
{
foreach (var dir in directories)
{
token.ThrowIfCancellationRequested();
await Request.Yield(); // Allow pause/cancel
var files = Directory.GetFiles(dir, pattern);
lock (results)
{
results.AddRange(files);
}
processed++;
progress.Report((float)processed / directories.Length);
}
return true;
});
await request.Task;
return results;
}
}
// Usage:
var scanner = new DirectoryScanner();
var foundFiles = await scanner.FindFilesAsync(
"C:\\Data",
"*.log",
new Progress<float>(p => Console.WriteLine($"Scanning: {p:P}"))
);
Console.WriteLine($"Found {foundFiles.Count} files");public async Task ProcessFilesAsync(string[] filePaths)
{
foreach (var filePath in filePaths)
{
// Create pipeline: Read → Validate → Process → Save
var readRequest = new OwnRequest(async token =>
{
var data = await File.ReadAllTextAsync(filePath, token);
return !string.IsNullOrEmpty(data);
});
var validateRequest = new OwnRequest(async token =>
{
// Validation logic
await Task.Delay(100, token);
return true;
});
var processRequest = new OwnRequest(async token =>
{
// Processing logic
await Task.Delay(500, token);
return true;
});
var saveRequest = new OwnRequest(async token =>
{
await File.WriteAllTextAsync($"{filePath}.processed", "result", token);
return true;
});
// Chain them
readRequest.Options.SubsequentRequest = validateRequest;
validateRequest.Options.SubsequentRequest = processRequest;
processRequest.Options.SubsequentRequest = saveRequest;
// Start only the first - rest follow automatically
readRequest.Start();
}
await ParallelRequestHandler.MainRequestHandler.Task;
}public class RateLimitedApiClient
{
private readonly HttpClient _client = new();
private readonly ParallelRequestHandler _handler;
private int _remainingRequests = 100;
private readonly SemaphoreSlim _rateLimiter = new(10, 10);
public RateLimitedApiClient()
{
_handler = new ParallelRequestHandler
{
AutoParallelism = () =>
{
// Adjust concurrency based on remaining quota
if (_remainingRequests < 10)
return 1; // Throttle down
else if (_remainingRequests < 50)
return 3;
else
return 10;
},
MaxParallelism = 10
};
// Reset rate limit every minute
_ = Task.Run(async () =>
{
while (true)
{
await Task.Delay(TimeSpan.FromMinutes(1));
Interlocked.Exchange(ref _remainingRequests, 100);
Console.WriteLine("Rate limit reset to 100");
}
});
}
public async Task<string> GetAsync(string url)
{
await _rateLimiter.WaitAsync();
try
{
var request = new OwnRequest(async token =>
{
var response = await _client.GetAsync(url, token);
if (response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
{
Console.WriteLine("Rate limited by server, retrying...");
return false; // Trigger retry
}
Interlocked.Decrement(ref _remainingRequests);
return response.IsSuccessStatusCode;
}, new()
{
Handler = _handler,
NumberOfAttempts = 5,
DelayBetweenAttempts = TimeSpan.FromSeconds(10)
});
await request.Task;
if (request.State == RequestState.Completed)
return "Success";
else
throw new Exception("Request failed");
}
finally
{
_rateLimiter.Release();
}
}
}
// Usage:
var client = new RateLimitedApiClient();
var tasks = Enumerable.Range(0, 200)
.Select(i => client.GetAsync($"https://api.example.com/data/{i}"));
await Task.WhenAll(tasks);public class WebScraper
{
private readonly HttpClient _client = new();
public async Task<Dictionary<string, string>> ScrapeUrlsAsync(string[] urls)
{
var results = new ConcurrentDictionary<string, string>();
var requests = urls.Select(url => new OwnRequest(async token =>
{
var response = await _client.GetAsync(url, token);
if (!response.IsSuccessStatusCode)
return false; // Retry
var html = await response.Content.ReadAsStringAsync(token);
results[url] = html;
Console.WriteLine($"Scraped: {url}");
return true;
}, new()
{
Priority = url.Contains("important") ? RequestPriority.High : RequestPriority.Normal,
NumberOfAttempts = 3
})).ToArray();
// Group in container for unified control
var container = new RequestContainer<OwnRequest>(requests);
// Monitor state
container.StateChanged += (sender, state) =>
{
Console.WriteLine($"Container state: {state}");
};
await container.Task;
return results.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
}public class BatchInserter
{
private readonly string _connectionString;
public BatchInserter(string connectionString)
{
_connectionString = connectionString;
}
public async Task InsertBatchAsync<T>(IEnumerable<T> items, int batchSize = 100)
{
var batches = items.Chunk(batchSize);
var handler = new ParallelRequestHandler { StaticDegreeOfParallelism = 5 };
foreach (var batch in batches)
{
var request = new OwnRequest(async token =>
{
using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(token);
using var transaction = connection.BeginTransaction();
try
{
foreach (var item in batch)
{
token.ThrowIfCancellationRequested();
await InsertItemAsync(connection, transaction, item, token);
}
await transaction.CommitAsync(token);
return true;
}
catch
{
await transaction.RollbackAsync(token);
return false; // Retry entire batch
}
}, new()
{
Handler = handler,
NumberOfAttempts = 3,
DelayBetweenAttempts = TimeSpan.FromSeconds(5)
});
}
await handler.Task;
}
private async Task InsertItemAsync<T>(
SqlConnection conn,
SqlTransaction trans,
T item,
CancellationToken token)
{
// Insert logic
await Task.Delay(10, token); // Simulate insert
}
}public class DatabaseMigration
{
public async Task MigrateAsync(string[] migrationScripts)
{
var handler = new SequentialRequestHandler(); // One at a time, in order
foreach (var script in migrationScripts.OrderBy(s => s))
{
var request = new OwnRequest(async token =>
{
Console.WriteLine($"Executing migration: {script}");
using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(token);
var sql = await File.ReadAllTextAsync(script, token);
using var command = new SqlCommand(sql, connection);
await command.ExecuteNonQueryAsync(token);
Console.WriteLine($"Completed: {script}");
return true;
}, new()
{
Handler = handler,
NumberOfAttempts = 1 // Don't retry migrations
});
}
await handler.Task;
}
}public class AssetLoader
{
private readonly ParallelRequestHandler _handler = new()
{
AutoParallelism = () =>
{
// Load more assets when GPU is idle
float gpuUsage = GetGPUUsage();
return gpuUsage < 0.5f ? 8 : 2;
},
MaxParallelism = 8
};
public async Task LoadAssetsAsync(AssetManifest manifest)
{
// Critical assets (UI, player) load first
var criticalAssets = manifest.CriticalAssets.Select(asset =>
new OwnRequest(async token =>
{
await LoadAssetAsync(asset, token);
return true;
}, new()
{
Handler = _handler,
Priority = RequestPriority.High
})
);
// Background assets (scenery, audio) load later
var backgroundAssets = manifest.BackgroundAssets.Select(asset =>
new OwnRequest(async token =>
{
await LoadAssetAsync(asset, token);
return true;
}, new()
{
Handler = _handler,
Priority = RequestPriority.Low
})
);
// When game is paused/backgrounded
Application.OnPause += () => _handler.Pause();
Application.OnResume += () => _handler.Start();
await _handler.Task;
}
private float GetGPUUsage()
{
// Platform-specific GPU query
return 0.3f;
}
}public class WorldStreamer
{
private readonly ParallelRequestHandler _handler = new()
{
StaticDegreeOfParallelism = 4
};
public async Task StreamChunksAsync(Vector3 playerPosition, float radius)
{
var chunksToLoad = CalculateChunksInRadius(playerPosition, radius);
var requests = new List<OwnRequest>();
foreach (var chunkPos in chunksToLoad)
{
float distance = Vector3.Distance(playerPosition, chunkPos);
// Closer chunks have higher priority
var priority = distance < radius / 3 ? RequestPriority.High :
distance < radius * 2 / 3 ? RequestPriority.Normal :
RequestPriority.Low;
var request = new OwnRequest(async token =>
{
await Request.Yield(); // Allow interruption for player movement
var chunkData = await LoadChunkDataAsync(chunkPos, token);
await GenerateMeshAsync(chunkData, token);
return true;
}, new()
{
Handler = _handler,
Priority = priority
});
requests.Add(request);
}
// Don't wait - chunks load in background
// await _handler.Task; // Optional
}
}public class FileUploader
{
public async Task UploadFilesAsync(string[] filePaths, IProgress<float> overallProgress)
{
var requests = filePaths.Select(path => new ProgressableFileRequest(path)).ToArray();
var container = new ProgressableContainer<ProgressableFileRequest>(requests);
// Subscribe to aggregated progress
container.Progress.ProgressChanged += (sender, progress) =>
{
overallProgress.Report(progress);
};
await container.Task;
}
}
public class ProgressableFileRequest : Request<RequestOptions<VoidStruct, VoidStruct>, VoidStruct, VoidStruct>,
IProgressableRequest
{
private readonly string _filePath;
private readonly Progress<float> _progress = new();
public Progress<float> Progress => _progress;
public ProgressableFileRequest(string filePath)
{
_filePath = filePath;
AutoStart();
}
protected override async Task<RequestReturn> RunRequestAsync()
{
var fileInfo = new FileInfo(_filePath);
long totalBytes = fileInfo.Length;
long uploadedBytes = 0;
using var fileStream = File.OpenRead(_filePath);
var buffer = new byte[8192];
while (uploadedBytes < totalBytes)
{
await Request.Yield();
int bytesRead = await fileStream.ReadAsync(buffer, Token);
if (bytesRead == 0)
break;
// Simulate upload
await Task.Delay(10, Token);
uploadedBytes += bytesRead;
((IProgress<float>)_progress).Report((float)uploadedBytes / totalBytes);
}
return new RequestReturn { Successful = true };
}
}
// Usage:
var uploader = new FileUploader();
await uploader.UploadFilesAsync(
new[] { "file1.dat", "file2.dat", "file3.dat" },
new Progress<float>(p => Console.WriteLine($"Upload progress: {p:P}"))
);public class ProcessingDashboard
{
public async Task ProcessWithDashboardAsync(IEnumerable<string> items)
{
var requests = items.Select(item => new ProgressableDataProcessor(item)).ToArray();
var container = new ProgressableContainer<ProgressableDataProcessor>(requests);
// Update UI in real-time
container.StateChanged += (sender, state) =>
{
UpdateDashboardState(state);
};
container.Progress.ProgressChanged += (sender, progress) =>
{
UpdateProgressBar(progress);
};
// Display stats every second
_ = Task.Run(async () =>
{
while (container.State != RequestState.Completed)
{
await Task.Delay(1000);
int completed = requests.Count(r => r.State == RequestState.Completed);
int running = requests.Count(r => r.State == RequestState.Running);
int failed = requests.Count(r => r.State == RequestState.Failed);
Console.WriteLine($"Completed: {completed}, Running: {running}, Failed: {failed}");
}
});
await container.Task;
}
}public class RequestPool<T>
{
private readonly ConcurrentBag<OwnRequest> _pool = new();
private readonly Func<T, CancellationToken, Task<bool>> _workFunc;
public RequestPool(Func<T, CancellationToken, Task<bool>> workFunc)
{
_workFunc = workFunc;
}
public async Task ExecuteAsync(T item)
{
if (!_pool.TryTake(out var request))
{
// Create new request
request = new OwnRequest(async token => await _workFunc(item, token),
new() { AutoStart = false });
}
// Reset and reuse
request.TrySetIdle();
request.Start();
await request.Task;
// Return to pool
_pool.Add(request);
}
}public async Task ProcessConditionalWorkflowAsync(string dataPath)
{
var loadRequest = new OwnRequest(async token =>
{
var data = await File.ReadAllTextAsync(dataPath, token);
bool isValid = ValidateData(data);
if (isValid)
{
// Success path
var processRequest = new OwnRequest(async token =>
{
await ProcessValidDataAsync(data, token);
return true;
});
Options.SubsequentRequest = processRequest;
}
else
{
// Error path
var errorRequest = new OwnRequest(async token =>
{
await LogErrorAsync($"Invalid data in {dataPath}", token);
return true;
});
Options.SubsequentRequest = errorRequest;
}
return isValid;
});
await loadRequest.Task;
}public async Task<TResult> FanOutFanInAsync<TInput, TResult>(
TInput[] inputs,
Func<TInput, CancellationToken, Task<TResult>> processFunc,
Func<TResult[], TResult> aggregateFunc)
{
var results = new ConcurrentDictionary<int, TResult>();
var requests = inputs.Select((input, index) => new OwnRequest(async token =>
{
var result = await processFunc(input, token);
results[index] = result;
return true;
})).ToArray();
var container = new RequestContainer<OwnRequest>(requests);
await container.Task;
// Aggregate results in order
var orderedResults = results.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToArray();
return aggregateFunc(orderedResults);
}
// Usage:
var sum = await FanOutFanInAsync(
new[] { 1, 2, 3, 4, 5 },
async (num, token) =>
{
await Task.Delay(100, token);
return num * 2;
},
results => results.Sum()
);
Console.WriteLine($"Sum: {sum}"); // 30These examples demonstrate:
-
$\text{\color{lightblue}Basic Patterns}$ : Simple requests, configuration, manual control -
$\text{\color{orange}File Operations}$ : Batch downloads, directory scanning, pipelines -
$\text{\color{blue}HTTP Requests}$ : Rate limiting, parallel scraping, API integration -
$\text{\color{purple}Database Operations}$ : Batch inserts, sequential migrations -
$\text{\color{red}Game Development}$ : Asset loading, world streaming, priority management -
$\text{\color{green}Progress Tracking}$ : Multi-file uploads, real-time dashboards -
$\text{\color{orange}Advanced Patterns}$ : Request pooling, conditional workflows, fan-out/fan-in
Adapt these patterns to your specific use cases.