Appearance
Multi-Tenancy
GrydJobs integrates with Gryd.IO's multi-tenancy infrastructure to provide automatic tenant isolation across all job operations.
How It Works
- Job Enqueue — The current tenant ID is captured when a job is enqueued
- Job Execution — Tenant context is restored before the job executes
- Data Isolation — All queries filter by tenant via
ITenantQueryContext - Dashboard — Stats and listings respect tenant boundaries
Tenant Context Propagation
When a job is enqueued from a tenant-scoped request, the tenant ID is automatically:
- Stored in the
JobDefinition.TenantIdfield - Passed to the Hangfire job payload
- Restored via
TenantContextAccessorwhen the job executes
csharp
// Tenant context is automatically captured from the current request
await scheduler.EnqueueAsync<SendEmailJob, SendEmailArgs>(
new SendEmailArgs(email, subject, body));
// The job will execute with the same tenant contextDatabase Isolation
The JobsDbContext implements ITenantQueryContext, which automatically applies tenant filters to all EF Core queries:
csharp
// All repositories automatically filter by tenant
var jobs = await jobStore.GetAllAsync(parameters); // Only returns current tenant's jobs
var stats = await jobStore.GetDashboardStatsAsync(); // Stats scoped to tenantAPI Endpoints
All API endpoints respect tenant context via the ITenantOptionalAware interface on MediatR commands/queries:
csharp
// Commands automatically get tenant ID from the pipeline behavior
public sealed record EnqueueJobCommand(...) : IRequest<Result<JobSummaryDto>>,
ITenantOptionalAware
{
public Guid TenantId { get; set; } // Injected by TenantBehavior
}Cross-Tenant Operations
Some operations (like DLQ purge) can bypass tenant filtering when needed:
csharp
// PurgeDeadLetterQueueCommand implements IIgnoreTenantFilter
// This allows system-wide cleanup regardless of tenant
public sealed record PurgeDeadLetterQueueCommand(int? RetentionDays)
: IRequest<Result>, IIgnoreTenantFilter;Recurring Jobs
Recurring jobs can be tenant-scoped:
csharp
var schedule = JobSchedule.Create(
"tenant-report",
"MyApp.TenantReportJob",
"0 8 * * 1", // Every Monday at 8:00 AM
timeZoneId: null,
queue: "default",
tenantId: currentTenantId // Scoped to this tenant
);