A .NET library and CLI tool for creating scheduled automation jobs. Provides APIs for database operations, file management, HTTP requests, email sending, and heartbeat monitoring.
Write a script that queries a database, processes data, and sends an email report -- all scheduled via cron or Task Scheduler.
using Noundry.Jobs.Database;
using Noundry.Jobs.Email;
using Noundry.Jobs.Files;
// Connect to database
var db = new JobsDb("Host=localhost;Database=mydb;Username=user;Password=pass;",
DatabaseType.PostgreSql);
// Query data
var orders = await db.QueryAsync<Order>(
"SELECT * FROM orders WHERE created_at >= @StartDate",
new { StartDate = DateTime.UtcNow.AddDays(-1) });
// Write report
var report = $"Daily Orders: {orders.Count()}";
await JobsFile.WriteAllTextAsync("report.txt", report);
// Send email
var email = new JobsEmail("smtp.example.com", 587, "user", "pass");
await email.SendAsync(new EmailMessage
{
From = "jobs@company.com",
To = "team@company.com",
Subject = "Daily Order Report",
Body = report
});Query, insert, update, delete across SQL Server, PostgreSQL, MySQL, and SQLite. Powered by Noundry.Tuxedo ORM.
Static API for file read/write, copy, move, delete, directory listing, and recursive operations.
Fluent HTTP client with GET/POST/PUT/PATCH/DELETE, authentication, file upload/download, and typed responses.
Send emails via SMTP with HTML bodies and file attachments. Built on MailKit.
Supports SQL Server, PostgreSQL, MySQL, and SQLite with parameterized queries and transactions.
// Initialize for different databases
var pg = new JobsDb("Host=localhost;Database=mydb;...", DatabaseType.PostgreSql);
var sql = new JobsDb("Server=localhost;Database=mydb;...");
var lite = new JobsDb("Data Source=local.db", DatabaseType.Sqlite);
// Query operations
var users = await db.QueryAsync<User>("SELECT * FROM users WHERE active = @Active",
new { Active = true });
var user = await db.QueryFirstOrDefaultAsync<User>(
"SELECT * FROM users WHERE id = @Id", new { Id = 123 });
var count = await db.ExecuteScalarAsync<long>("SELECT COUNT(*) FROM users");
// Execute with parameters
await db.ExecuteAsync("DELETE FROM logs WHERE created_at < @CutoffDate",
new { CutoffDate = DateTime.UtcNow.AddDays(-90) });
// Transaction
await db.ExecuteInTransactionAsync(async conn =>
{
await db.ExecuteAsync("INSERT INTO orders ...", new { ... });
await db.ExecuteAsync("UPDATE inventory ...", new { ... });
// Auto-rollback on exception, auto-commit on success
});All methods are static. Covers read, write, copy, move, delete, and directory operations.
// Read/Write
var content = await JobsFile.ReadAllTextAsync("config.json");
await JobsFile.WriteAllTextAsync("output.txt", "Hello, World!");
JobsFile.WriteAllText("log.txt", logEntry, append: true);
// Copy/Move/Delete
await JobsFile.CopyAsync("source.txt", "backup/source.txt");
JobsFile.Move("temp.txt", "final.txt");
JobsFile.Delete("temp.txt"); // safe - no error if missing
int deleted = JobsFile.DeleteMany("/logs", "*.log");
// Directory operations
JobsFile.CreateDirectory("/data/output/reports");
var files = JobsFile.List("/data", "*.csv", recursive: true);
JobsFile.CopyDirectory("/source", "/backup");Fluent HTTP client with built-in authentication, typed responses, and file operations.
var api = new JobsApi()
.WithBaseUrl("https://api.example.com")
.WithBearerToken("sk-abc123")
.WithTimeout(TimeSpan.FromSeconds(30));
// Typed GET request
var users = await api.GetAsync<List<User>>("/users");
// POST with payload
var result = await api.PostAsync<OrderResponse>("/orders", new { ProductId = 1, Qty = 5 });
// Download/Upload files
await api.DownloadFileAsync("/reports/daily.pdf", "report.pdf");
await api.UploadFileAsync("/uploads", "data.csv");| Method | Description |
|---|---|
WithBearerToken(token) | Set Bearer token auth header |
WithBasicAuth(user, pass) | Set Basic auth header |
WithApiKey(header, key) | Set custom API key header |
WithHeader(name, value) | Set any custom header |
var email = new JobsEmail("smtp.office365.com", 587, "user@company.com", "password");
await email.SendAsync(new EmailMessage
{
From = "jobs@company.com",
To = "team@company.com",
Subject = "Daily Report",
Body = "<h1>Report</h1><p>All systems operational.</p>",
IsHtml = true,
Attachments = new List<string> { "report.csv", "chart.png" }
});Schedule and run jobs from the command line using .csx script files.
# Run a job script
$ njobs run daily-report.csx
# Schedule with cron (Linux)
$ njobs schedule --script daily-report.csx --cron "0 8 * * *"
# List scheduled jobs
$ njobs listSend heartbeat signals to Noundry Jobs Monitor for job monitoring. Alerts you when scheduled jobs fail to run.
var heartbeat = new JobsHeartbeat("https://jobs.noundry.com", "your-api-key");
// Signal job start
await heartbeat.StartAsync("daily-report");
// ... run job ...
// Signal job complete
await heartbeat.CompleteAsync("daily-report");
// Or signal failure
await heartbeat.FailAsync("daily-report", "Database connection timeout");A practical example combining database, file, and email APIs to process CSV files, generate a report, and notify your team.
using Noundry.Jobs.Database;
using Noundry.Jobs.Files;
using Noundry.Jobs.Email;
using Noundry.Jobs.Heartbeat;
var heartbeat = new JobsHeartbeat("https://jobs.noundry.com", "key");
await heartbeat.StartAsync("csv-pipeline");
try
{
var inputDir = "/data/input";
var archiveDir = "/data/archive";
JobsFile.CreateDirectory(archiveDir);
// Process all CSV files in input directory
foreach (var file in JobsFile.List(inputDir, "*.csv"))
{
var content = await JobsFile.ReadAllTextAsync(file);
// ... process content ...
// Archive with timestamp
var name = $"{Path.GetFileNameWithoutExtension(file)}_{DateTime.UtcNow:yyyyMMdd}.csv";
JobsFile.Move(file, Path.Combine(archiveDir, name));
}
// Cleanup old archives (older than 90 days)
var db = new JobsDb(connStr, DatabaseType.PostgreSql);
await db.ExecuteAsync("DELETE FROM logs WHERE created < @Cut",
new { Cut = DateTime.UtcNow.AddDays(-90) });
await heartbeat.CompleteAsync("csv-pipeline");
}
catch (Exception ex)
{
await heartbeat.FailAsync("csv-pipeline", ex.Message);
throw;
}| Database | Enum Value | Connection String Example |
|---|---|---|
| SQL Server | DatabaseType.SqlServer | Server=localhost;Database=mydb;... |
| PostgreSQL | DatabaseType.PostgreSql | Host=localhost;Database=mydb;... |
| MySQL | DatabaseType.MySql | Server=localhost;Database=mydb;... |
| SQLite | DatabaseType.Sqlite | Data Source=local.db |
Default is DatabaseType.SqlServer when no type is specified. All operations support parameterized queries to prevent SQL injection.