007
無料Security audit, hardening, threat modeling (STRIDE/PASTA), Red/Blue Team, OWASP checks, code review, incident response, and infrastructure security for any project.
日本語の概要は準備中です。原文の説明を表示しています。
Generates scheduled background jobs using Quartz.NET. Includes job definitions, triggers, cron scheduling, dependency injection, and persistent job store configuration.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Quartz.NET is a full-featured job scheduling library:
| Component | Purpose |
|---|---|
IJob | Job interface to implement |
IConfigureOptions<QuartzOptions> | Job registration |
JobKey | Unique job identifier |
TriggerBuilder | Defines when job runs |
CronScheduleBuilder | Cron-based scheduling |
SimpleScheduleBuilder | Interval-based scheduling |
/Infrastructure/
├── BackgroundJobs/
│ ├── {JobName}Job.cs
│ ├── {JobName}JobSetup.cs
│ └── ...
└── DependencyInjection.cs
// src/{name}.infrastructure/BackgroundJobs/ProcessPendingOrdersJob.cs
using Microsoft.Extensions.Logging;
using Quartz;
namespace {name}.infrastructure.backgroundjobs;
/// <summary>
/// Processes pending orders every 5 minutes
/// </summary>
[DisallowConcurrentExecution] // Prevent overlapping executions
public sealed class ProcessPendingOrdersJob : IJob
{
private readonly IOrderRepository _orderRepository;
private readonly IOrderProcessor _orderProcessor;
private readonly ILogger<ProcessPendingOrdersJob> _logger;
public ProcessPendingOrdersJob(
IOrderRepository orderRepository,
IOrderProcessor orderProcessor,
ILogger<ProcessPendingOrdersJob> logger)
{
_orderRepository = orderRepository;
_orderProcessor = orderProcessor;
_logger = logger;
}
public async Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("Starting pending orders processing...");
try
{
var pendingOrders = await _orderRepository
.GetPendingOrdersAsync(context.CancellationToken);
_logger.LogInformation(
"Found {Count} pending orders to process",
pendingOrders.Count);
foreach (var order in pendingOrders)
{
try
{
await _orderProcessor.ProcessAsync(order, context.CancellationToken);
_logger.LogInformation(
"Processed order {OrderId}",
order.Id);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Failed to process order {OrderId}",
order.Id);
}
}
_logger.LogInformation("Completed pending orders processing");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in pending orders processing job");
throw; // Quartz will handle retry based on configuration
}
}
}
// src/{name}.infrastructure/BackgroundJobs/ProcessPendingOrdersJobSetup.cs
using Microsoft.Extensions.Options;
using Quartz;
namespace {name}.infrastructure.backgroundjobs;
internal sealed class ProcessPendingOrdersJobSetup
: IConfigureOptions<QuartzOptions>
{
public void Configure(QuartzOptions options)
{
var jobKey = JobKey.Create(nameof(ProcessPendingOrdersJob));
options
.AddJob<ProcessPendingOrdersJob>(jobBuilder =>
jobBuilder
.WithIdentity(jobKey)
.WithDescription("Processes pending orders"))
.AddTrigger(triggerBuilder =>
triggerBuilder
.ForJob(jobKey)
.WithIdentity($"{nameof(ProcessPendingOrdersJob)}-trigger")
.WithSimpleSchedule(schedule =>
schedule
.WithIntervalInMinutes(5)
.RepeatForever())
.StartNow());
}
}
// src/{name}.infrastructure/BackgroundJobs/DailyReportJob.cs
using Microsoft.Extensions.Logging;
using Quartz;
namespace {name}.infrastructure.backgroundjobs;
/// <summary>
/// Generates daily reports at 6:00 AM every day
/// </summary>
[DisallowConcurrentExecution]
public sealed class DailyReportJob : IJob
{
private readonly IReportService _reportService;
private readonly IEmailService _emailService;
private readonly ILogger<DailyReportJob> _logger;
public DailyReportJob(
IReportService reportService,
IEmailService emailService,
ILogger<DailyReportJob> logger)
{
_reportService = reportService;
_emailService = emailService;
_logger = logger;
}
public async Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("Starting daily report generation...");
var reportDate = DateTime.UtcNow.Date.AddDays(-1);
var report = await _reportService.GenerateDailyReportAsync(
reportDate,
context.CancellationToken);
await _emailService.SendReportAsync(
report,
context.CancellationToken);
_logger.LogInformation(
"Daily report for {Date} sent successfully",
reportDate.ToShortDateString());
}
}
// src/{name}.infrastructure/BackgroundJobs/DailyReportJobSetup.cs
using Microsoft.Extensions.Options;
using Quartz;
namespace {name}.infrastructure.backgroundjobs;
internal sealed class DailyReportJobSetup : IConfigureOptions<QuartzOptions>
{
public void Configure(QuartzOptions options)
{
var jobKey = JobKey.Create(nameof(DailyReportJob));
options
.AddJob<DailyReportJob>(jobBuilder =>
jobBuilder
.WithIdentity(jobKey)
.WithDescription("Daily report generation"))
.AddTrigger(triggerBuilder =>
triggerBuilder
.ForJob(jobKey)
.WithIdentity($"{nameof(DailyReportJob)}-trigger")
.WithCronSchedule(
"0 0 6 * * ?", // 6:00 AM every day
builder => builder.InTimeZone(TimeZoneInfo.Utc))
.WithDescription("Fires at 6:00 AM UTC daily"));
}
}
| Expression | Description |
|---|---|
0 0 * * * ? | Every hour at minute 0 |
0 0/15 * * * ? | Every 15 minutes |
0 0 6 * * ? | Daily at 6:00 AM |
0 0 6 ? * MON-FRI | Weekdays at 6:00 AM |
0 0 0 1 * ? | First day of month at midnight |
0 0 0 L * ? | Last day of month at midnight |
0 0 12 ? * SUN | Every Sunday at noon |
Format: seconds minutes hours day-of-month month day-of-week [year]
| Field | Values |
|---|---|
| Seconds | 0-59 |
| Minutes | 0-59 |
| Hours | 0-23 |
| Day-of-month | 1-31, L (last), W (weekday) |
| Month | 1-12 or JAN-DEC |
| Day-of-week | 1-7 or SUN-SAT, L (last) |
| Year | Optional, 1970-2099 |
Special Characters:
* - All values? - No specific value (day-of-month/day-of-week)- - Range (e.g., MON-FRI), - List (e.g., MON,WED,FRI)/ - Increment (e.g., 0/15 = every 15)L - Last (e.g., last day of month)W - Nearest weekday# - Nth day (e.g., 2#3 = third Monday)// src/{name}.infrastructure/BackgroundJobs/SendScheduledEmailJob.cs
using Microsoft.Extensions.Logging;
using Quartz;
namespace {name}.infrastructure.backgroundjobs;
/// <summary>
/// Sends a scheduled email using data from JobDataMap
/// </summary>
public sealed class SendScheduledEmailJob : IJob
{
public const string EmailIdKey = "EmailId";
public const string RecipientKey = "Recipient";
private readonly IEmailService _emailService;
private readonly ILogger<SendScheduledEmailJob> _logger;
public SendScheduledEmailJob(
IEmailService emailService,
ILogger<SendScheduledEmailJob> logger)
{
_emailService = emailService;
_logger = logger;
}
public async Task Execute(IJobExecutionContext context)
{
// Get data from job data map
var dataMap = context.MergedJobDataMap;
var emailId = dataMap.GetGuid(EmailIdKey);
var recipient = dataMap.GetString(RecipientKey);
_logger.LogInformation(
"Sending scheduled email {EmailId} to {Recipient}",
emailId,
recipient);
await _emailService.SendScheduledEmailAsync(
emailId,
context.CancellationToken);
}
}
// Scheduling the job with data
public class EmailScheduler
{
private readonly ISchedulerFactory _schedulerFactory;
public async Task ScheduleEmailAsync(
Guid emailId,
string recipient,
DateTime sendAt)
{
var scheduler = await _schedulerFactory.GetScheduler();
var jobKey = new JobKey($"email-{emailId}", "scheduled-emails");
var job = JobBuilder.Create<SendScheduledEmailJob>()
.WithIdentity(jobKey)
.UsingJobData(SendScheduledEmailJob.EmailIdKey, emailId.ToString())
.UsingJobData(SendScheduledEmailJob.RecipientKey, recipient)
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity($"email-{emailId}-trigger", "scheduled-emails")
.StartAt(sendAt)
.Build();
await scheduler.ScheduleJob(job, trigger);
}
}
// src/{name}.infrastructure/BackgroundJobs/SyncExternalDataJob.cs
using Microsoft.Extensions.Logging;
using Quartz;
namespace {name}.infrastructure.backgroundjobs;
/// <summary>
/// Syncs data from external API with retry support
/// </summary>
[DisallowConcurrentExecution]
[PersistJobDataAfterExecution] // Persist data map changes
public sealed class SyncExternalDataJob : IJob
{
private const int MaxRetries = 3;
private const string RetryCountKey = "RetryCount";
private readonly IExternalApiClient _apiClient;
private readonly IDataSyncService _syncService;
private readonly ILogger<SyncExternalDataJob> _logger;
public SyncExternalDataJob(
IExternalApiClient apiClient,
IDataSyncService syncService,
ILogger<SyncExternalDataJob> logger)
{
_apiClient = apiClient;
_syncService = syncService;
_logger = logger;
}
public async Task Execute(IJobExecutionContext context)
{
var retryCount = context.MergedJobDataMap.GetInt(RetryCountKey);
try
{
_logger.LogInformation(
"Starting external data sync (attempt {Attempt})",
retryCount + 1);
var data = await _apiClient.FetchDataAsync(context.CancellationToken);
await _syncService.SyncAsync(data, context.CancellationToken);
// Reset retry count on success
context.JobDetail.JobDataMap.Put(RetryCountKey, 0);
_logger.LogInformation("External data sync completed successfully");
}
catch (Exception ex)
{
_logger.LogError(
ex,
"External data sync failed (attempt {Attempt} of {MaxRetries})",
retryCount + 1,
MaxRetries);
if (retryCount < MaxRetries - 1)
{
// Increment retry count
context.JobDetail.JobDataMap.Put(RetryCountKey, retryCount + 1);
// Throw to trigger Quartz retry
throw new JobExecutionException(ex, refireImmediately: false);
}
else
{
// Max retries reached, log and don't retry
_logger.LogCritical(
"External data sync failed after {MaxRetries} attempts. Manual intervention required.",
MaxRetries);
context.JobDetail.JobDataMap.Put(RetryCountKey, 0);
}
}
}
}
// src/{name}.infrastructure/DependencyInjection.cs
using Quartz;
using Microsoft.Extensions.DependencyInjection;
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration)
{
// ... other registrations
AddBackgroundJobs(services, configuration);
return services;
}
private static void AddBackgroundJobs(
IServiceCollection services,
IConfiguration configuration)
{
services.AddQuartz(configure =>
{
// ═══════════════════════════════════════════════════════════════
// IN-MEMORY STORE (Development)
// ═══════════════════════════════════════════════════════════════
configure.UseInMemoryStore();
// ═══════════════════════════════════════════════════════════════
// PERSISTENT STORE (Production - uncomment for production)
// ═══════════════════════════════════════════════════════════════
// configure.UsePersistentStore(store =>
// {
// store.UsePostgres(configuration.GetConnectionString("Database")!);
// store.UseJsonSerializer();
// store.PerformSchemaValidation = true;
// });
// ═══════════════════════════════════════════════════════════════
// CLUSTERING (Multi-instance - uncomment for distributed)
// ═══════════════════════════════════════════════════════════════
// configure.UsePersistentStore(store =>
// {
// store.UsePostgres(configuration.GetConnectionString("Database")!);
// store.UseJsonSerializer();
// store.UseClustering(cluster =>
// {
// cluster.CheckinMisfireThreshold = TimeSpan.FromSeconds(20);
// cluster.CheckinInterval = TimeSpan.FromSeconds(10);
// });
// });
});
// Register hosted service
services.AddQuartzHostedService(options =>
{
options.WaitForJobsToComplete = true;
options.AwaitApplicationStarted = true;
});
// Register job setups
services.ConfigureOptions<ProcessPendingOrdersJobSetup>();
services.ConfigureOptions<DailyReportJobSetup>();
services.ConfigureOptions<SyncExternalDataJobSetup>();
}
}
// src/{name}.infrastructure/BackgroundJobs/JobSchedulerService.cs
using Quartz;
namespace {name}.infrastructure.backgroundjobs;
/// <summary>
/// Service for dynamically scheduling jobs at runtime
/// </summary>
public interface IJobSchedulerService
{
Task ScheduleJobAsync<TJob>(DateTime runAt, JobDataMap? data = null)
where TJob : IJob;
Task ScheduleJobAsync<TJob>(TimeSpan delay, JobDataMap? data = null)
where TJob : IJob;
Task CancelJobAsync(string jobName, string groupName);
Task<bool> IsJobScheduledAsync(string jobName, string groupName);
}
internal sealed class JobSchedulerService : IJobSchedulerService
{
private readonly ISchedulerFactory _schedulerFactory;
public JobSchedulerService(ISchedulerFactory schedulerFactory)
{
_schedulerFactory = schedulerFactory;
}
public async Task ScheduleJobAsync<TJob>(DateTime runAt, JobDataMap? data = null)
where TJob : IJob
{
var scheduler = await _schedulerFactory.GetScheduler();
var jobName = $"{typeof(TJob).Name}-{Guid.NewGuid()}";
var jobBuilder = JobBuilder.Create<TJob>()
.WithIdentity(jobName, "dynamic-jobs");
if (data is not null)
{
jobBuilder.UsingJobData(data);
}
var job = jobBuilder.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity($"{jobName}-trigger", "dynamic-jobs")
.StartAt(runAt)
.Build();
await scheduler.ScheduleJob(job, trigger);
}
public async Task ScheduleJobAsync<TJob>(TimeSpan delay, JobDataMap? data = null)
where TJob : IJob
{
await ScheduleJobAsync<TJob>(DateTime.UtcNow.Add(delay), data);
}
public async Task CancelJobAsync(string jobName, string groupName)
{
var scheduler = await _schedulerFactory.GetScheduler();
await scheduler.DeleteJob(new JobKey(jobName, groupName));
}
public async Task<bool> IsJobScheduledAsync(string jobName, string groupName)
{
var scheduler = await _schedulerFactory.GetScheduler();
return await scheduler.CheckExists(new JobKey(jobName, groupName));
}
}
context.CancellationToken// ❌ WRONG: Long-running synchronous code
public Task Execute(IJobExecutionContext context)
{
Thread.Sleep(60000); // Don't block!
return Task.CompletedTask;
}
// ✅ CORRECT: Async operations
public async Task Execute(IJobExecutionContext context)
{
await Task.Delay(60000, context.CancellationToken);
}
// ❌ WRONG: Swallowing exceptions silently
public async Task Execute(IJobExecutionContext context)
{
try { await DoWork(); }
catch { } // Silent failure, no logging!
}
// ✅ CORRECT: Log and handle exceptions
public async Task Execute(IJobExecutionContext context)
{
try { await DoWork(); }
catch (Exception ex)
{
_logger.LogError(ex, "Job failed");
throw; // Let Quartz handle retry
}
}
// ❌ WRONG: Ignoring cancellation
public async Task Execute(IJobExecutionContext context)
{
foreach (var item in items)
{
await ProcessItem(item); // Ignores shutdown signal
}
}
// ✅ CORRECT: Respect cancellation
public async Task Execute(IJobExecutionContext context)
{
foreach (var item in items)
{
context.CancellationToken.ThrowIfCancellationRequested();
await ProcessItem(item, context.CancellationToken);
}
}
outbox-pattern - Outbox processor jobemail-service - Scheduled email jobsdotnet-clean-architecture - Infrastructure layer setupまだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Security audit, hardening, threat modeling (STRIDE/PASTA), Red/Blue Team, OWASP checks, code review, incident response, and infrastructure security for any project.
日本語の概要は準備中です。原文の説明を表示しています。
Guides the creation of agile user stories and Gherkin feature files. Use when the user wants to create a user story, write acceptance criteria, define Gherkin scenarios, or author BDD feature files. This should trigger for requests such as Create a user story; Write a user story; I need to write a user story. Part of cursor-rules-java project
日本語の概要は準備中です。原文の説明を表示しています。
Facilitates conversational discovery to create Architectural Decision Records (ADRs) for non-functional requirements using the ISO/IEC 25010:2023 quality model. Use when the user wants to document quality attributes, NFR decisions, security/performance/scalability architecture, or design systems with measurable quality criteria. This should trigger for requests such as Create ADR for Non-functional requirements; Document Non-functional requirements; Capture Non-functional requirements; Generate Non-functional requirements in an ADR. Part of cursor-rules-java project
日本語の概要は準備中です。原文の説明を表示しています。
Run a health check on an existing project: dependency audit, security scan, test runner detection, CI/CD evaluation, and missing configuration analysis. Maps the three execution gates (pre/in/post) from /10x-bootstrapper to an assessment framework for existing codebases. Reads optional context/foundation/stack-assessment.md from /10x-stack-assess to focus checks on identified gaps. Writes context/foundation/health-check.md with findings, prioritized fixes, and an agent-readiness verdict. Use when the user has an existing project and wants to verify its health before working with an agent. Trigger phrases: "health check", "check my project", "audit my project", "is my project healthy", "sprawdź projekt", "audyt projektu", "health-check", "project health". Use AFTER /10x-stack-assess (brownfield chain), BEFORE agent onboarding (m1-l4).
日本語の概要は準備中です。原文の説明を表示しています。
You MUST use this when building projects end-to-end. Orchestrates all 12 team roles — automatically switches between CTO, architect, PM, engineers, SRE, security, DBA, QA, and EM based on the current phase of work. Starts with brainstorming before any implementation.
日本語の概要は準備中です。原文の説明を表示しています。
Use when you need to add or configure Maven plugins in your pom.xml — including quality tools (enforcer, surefire, failsafe, jacoco, pitest, spotbugs, pmd), security scanning (OWASP), code formatting (Spotless), version management, container image build (Jib), build information tracking, and benchmarking (JMH) — through a consultative, modular step-by-step approach that only adds what you actually need. This should trigger for requests such as Add Maven plugins in pom.xml; Improve Maven plugins in pom.xml. Part of cursor-rules-java project
日本語の概要は準備中です。原文の説明を表示しています。