Token导航 LogoToken导航

Agent Skill · 前端设计

quartz-background-jobs(石英背景工作)

quartz-background-jobs 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

quartz-background-jobs 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为只读;许可证信息还不明确,第三方扫描已通过,按安装量在前端设计类的 10,216 个 Skill 里排第 7,947。

总安装 326周安装 14GitHub Stars 50下载 114核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:quartz-background-jobs(石英背景工作)
来源仓库:https://github.com/ronnythedev/dotnet-clean-architecture-skills
仓库路径:skills/quartz-background-jobs
安装命令:
npx skills add https://github.com/ronnythedev/dotnet-clean-architecture-skills --skill quartz-background-jobs
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/ronnythedev/dotnet-clean-architecture-skills --skill quartz-background-jobs

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

用于处理 GitHub 仓库和协作信息,支持 Issue 与 PR 管理。适合围绕代码变更和仓库状态进行整理与跟踪。quartz-background-jobs 属于前端设计类 Skill,可作为该场景下的辅助能力补充。可结合仓库 README 核验具体用法,提升协作效率。

安装前建议确认 token 权限和仓库访问范围。适用于 Codex、Claude、Cursor 等主流 AI 宿主环境。

来源仓库内路径:skills/quartz-background-jobs

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/ronnythedev/dotnet-clean-architecture-skills -…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它标注为只读,先用只读任务试一次,确认行为符合预期再扩大使用范围。

常见问题

6 条

quartz-background-jobs 怎么安装?

在终端执行 npx skills add https://github.com/ronnythedev/dotnet-clean-architecture-skills --skill qua…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

quartz-background-jobs 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

quartz-background-jobs 需要什么权限?

权限级别是只读。该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

quartz-background-jobs 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

quartz-background-jobs 用的人多吗?

公开数据是累计安装 326 次,近一周安装 14 次,下载 114 次,GitHub 50 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

quartz-background-jobs 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。
  • 标注为只读权限,试用阶段不容易误改本地文件。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。
  • 只想先试试效果、不希望它改动本地文件的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
quartz-background-jobs

石英背景工作 · 本页

32650只读未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Background Job Generator (Quartz)

Overview

Quartz.NET is a full-featured job scheduling library:

  • Job scheduling - Run tasks at specific times or intervals
  • Cron expressions - Complex scheduling patterns
  • Persistence - Jobs survive application restarts
  • Dependency injection - Full DI support
  • Clustering - Distributed job execution

Quick Reference

ComponentPurpose
IJobJob interface to implement
IConfigureOptions<QuartzOptions>Job registration
JobKeyUnique job identifier
TriggerBuilderDefines when job runs
CronScheduleBuilderCron-based scheduling
SimpleScheduleBuilderInterval-based scheduling

Job Structure

/Infrastructure/
├── BackgroundJobs/
│   ├── {JobName}Job.cs
│   ├── {JobName}JobSetup.cs
│   └── ...
└── DependencyInjection.cs

Template: Simple Interval Job

// 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
        }
    }
}

Template: Job Setup (IConfigureOptions)

// 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());
    }
}

Template: Cron Scheduled Job

// 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"));
    }
}

Cron Expression Reference

ExpressionDescription
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-FRIWeekdays 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? * SUNEvery Sunday at noon

Format: seconds minutes hours day-of-month month day-of-week [year]

FieldValues
Seconds0-59
Minutes0-59
Hours0-23
Day-of-month1-31, L (last), W (weekday)
Month1-12 or JAN-DEC
Day-of-week1-7 or SUN-SAT, L (last)
YearOptional, 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)

Template: Job with Data Map

// 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);
    }
}

Template: Job with Retry Logic

// 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);
            }
        }
    }
}

Template: Quartz Registration

// 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>();
    }
}

Template: Job Scheduler Service

// 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));
    }
}

Critical Rules

  1. Use [DisallowConcurrentExecution] - Prevent overlapping runs
  2. Handle exceptions properly - Log and decide retry strategy
  3. Use CancellationToken - From context.CancellationToken
  4. Keep jobs focused - One responsibility per job
  5. Use persistent store for production - Jobs survive restarts
  6. Time zones matter - Specify timezone for cron triggers
  7. Monitor job execution - Log start/end and duration
  8. Don't block the thread - Use async/await
  9. Inject scoped services - Each execution gets new scope
  10. Test job logic separately - Extract logic to testable services

Anti-Patterns to Avoid

// ❌ 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);
    }
}

Related Skills

  • outbox-pattern - Outbox processor job
  • email-service - Scheduled email jobs
  • dotnet-clean-architecture - Infrastructure layer setup

平台分布

Codex

35.36%
按下载量换算40

Claude

33.22%
按下载量换算38

Cursor

19.89%
按下载量换算23

Gemini CLI

9.01%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

只读

该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills