Giter VIP home page Giter VIP logo

sundial's Introduction

Sundial

license nuget dotNET China

.NET 功能齐全的开源分布式作业调度系统,可从最小的应用程序到大型企业系统使用。

Sundial.drawio

安装

dotnet add package Sundial

快速入门

我们在主页上有不少例子,这是让您入门的第一个:

  1. 定义作业,并实现 IJob 接口:
public class MyJob : IJob
{
    private readonly ILogger<MyJob> _logger;
    public MyJob(ILogger<MyJob> logger)
    {
        _logger = logger;
    }

    public Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
    {
        _logger.LogInformation(context.ToString());
        return Task.CompletedTask;
    }
}
  1. Startup.cs 注册 AddSchedule 服务和作业:
services.AddSchedule(options =>
{
    options.AddJob<MyJob>(Triggers.PeriodSeconds(5)); // 5s 执行一次
});
  1. 运行项目:
info: 2022-12-05 19:32:56.3835407 +08:00 星期一 L System.Logging.ScheduleService[0] #1
      Schedule hosted service is running.
info: 2022-12-05 19:32:56.3913451 +08:00 星期一 L System.Logging.ScheduleService[0] #1
      Schedule hosted service is preloading...
info: 2022-12-05 19:32:56.4322887 +08:00 星期一 L System.Logging.ScheduleService[0] #1
      The <job1_trigger1> trigger for scheduler of <job1> successfully appended to the schedule.
info: 2022-12-05 19:32:56.4347959 +08:00 星期一 L System.Logging.ScheduleService[0] #1
      The scheduler of <job1> successfully appended to the schedule.
warn: 2022-12-05 19:32:56.4504555 +08:00 星期一 L System.Logging.ScheduleService[0] #1
      Schedule hosted service preload completed, and a total of <1> schedulers are appended.
info: 2022-12-05 19:33:01.5100177 +08:00 星期一 L MyJob[0] #13
+     <job1> [C] <job1 job1_trigger1> 5s 1ts 2022-12-05 19:33:01.395 -> 2022-12-05 19:33:06.428
info: 2022-12-05 19:33:06.4676792 +08:00 星期一 L MyJob[0] #13
+     <job1> [C] <job1 job1_trigger1> 5s 2ts 2022-12-05 19:33:06.428 -> 2022-12-05 19:33:11.435
info: 2022-12-05 19:33:11.4460946 +08:00 星期一 L MyJob[0] #16
+     <job1> [C] <job1 job1_trigger1> 5s 3ts 2022-12-05 19:33:11.435 -> 2022-12-05 19:33:16.412

JobExecutionContext 重写了 ToString() 方法并提供以下几种格式:

# 持续运行格式
<作业Id> 作业描述 [并行C/串行S] <作业Id 触发器Id> 触发器字符串 触发器描述 触发次数ts 触发时间 -> 下一次触发时间

# 触发停止格式
<作业Id> 作业描述 [并行C/串行S] <作业Id 触发器Id> 触发器字符串 触发器描述 触发次数ts 触发时间 [触发器终止状态]

更多文档

文档

您可以在主页找到 Sundial 文档。

贡献

该存储库的主要目的是继续发展 Sundial 核心,使其更快、更易于使用。Sundial 的开发在 Gitee 上公开进行,我们感谢社区贡献错误修复和改进。

许可证

Sundial 采用 MIT 开源许可证。

sundial's People

Contributors

awxtggg avatar monksoul avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

sundial's Issues

IJob任务实例未被正确释放

任务在同时实现 IJob 和 IDisposable 的时候,在 ISchedulerFactory 被释放或相关任务被删除的时候,任务Dispose方法未被调用。

当前只能先手动调用 builder.Services.AddSingleton 将任务注册到 IServiceCollection 中,最后终止程序时才能任务实例被正确释放。

使用JobMonitor执行前后的时间问题和线程安全问题

开发环境版本

VS2022 17.7.3
net 6.0 Work Service程序
Sundial v2.25.0

该问题是怎么引起的?

Program.CS 代码

  services.AddSchedule(options =>
  {
      options.AddExecutor<JobExecutor>();
      options.AddMonitor<JobMonitor>();
      options.AddJob(JobBuilder.Create<MyJob>().SetIncludeAnnotations(true)); 
  });

JobExecutor代码

  public class JobExecutor : IJobExecutor
  {
      private readonly ILogger<JobExecutor> _logger;
      public JobExecutor(ILogger<JobExecutor> logger)
      {
          _logger = logger;
      }

      public async Task ExecuteAsync(JobExecutingContext context, IJob jobHandler, CancellationToken stoppingToken)
      {
          // 实现失败重试策略
          await Retry.InvokeAsync(async () =>
          {
              await jobHandler.ExecuteAsync(context, stoppingToken);
          }, context.Trigger.NumRetries, context.Trigger.RetryTimeout
          // 每次重试输出日志 
          , retryAction: (total, times) =>
          {
              _logger.LogWarning($"Retrying {times}/{total} times for 触发器{context.Trigger.TriggerId} 第{context.Trigger.NumberOfRuns}次执行的Job【{context.JobId}】");
          });
      }
  }

JobMonitor代码

    public class JobMonitor : IJobMonitor
    {
        private readonly ILogger<JobMonitor> _logger;
        private readonly ISchedulerFactory _schedulerFactory;
        public JobMonitor(ILogger<JobMonitor> logger, ISchedulerFactory schedulerFactory)
        {
            _logger = logger;
            _schedulerFactory = schedulerFactory;
        }

        public async Task OnExecutingAsync(JobExecutingContext context, CancellationToken stoppingToken)
        {
            _logger.LogInformation($"Job【{context.JobId}】第{context.Trigger.NumberOfRuns}次执行开始");
            await Task.CompletedTask;
        }

        public async Task OnExecutedAsync(JobExecutedContext context, CancellationToken stoppingToken)
        {
            if (context.Exception != null)
            {
                _logger.LogError(context.Exception,$"Job【{context.JobId}】for 触发器{context.Trigger.TriggerId} 第{context.Trigger.NumberOfRuns}次执行过程中出错啦,具体Job信息: {context.ConvertToJSON()},具体错误信息:{context.Exception}");
            }

            //context.Trigger.ElapsedTime不起作用?
            _logger.LogInformation($"Job【{context.JobId}】for 触发器{context.Trigger.TriggerId} 第{context.Trigger.NumberOfRuns}次执行结束,执行总耗时为{context.Trigger.ElapsedTime / 1000}秒");

            await Task.CompletedTask;
        }
    }

MyJob代码

  [JobDetail("MyJob", Concurrent = false, Description = "这是一段MyJob描述", GroupName = "MyService")]
  [PeriodSeconds(3, NumRetries = 3, RetryTimeout = 1000, TriggerId = "MyJobTrigger")]
  public class MyJob : IJob
  {
      private readonly ILogger<MyJob> _logger;
      public MyJob(ILogger<MyJob> logger)
      {
          _logger = logger;
      }

      public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
      {
          // 模拟运行第三次出异常
          if (context.Trigger.NumberOfRuns == 3)
          {
              throw new Exception("假装出错");
          }

          await Task.CompletedTask;
      }
  }

重现步骤

1. Concurrent = false 串行模式下JobMonitor的OnExecutedAsync中的获取当前context.Trigger.ElapsedTime时间异常
2. Concurrent = true 并行模式下JobMonitor的OnExecutedAsync中在1的基础上还出现线程安全问题导致输出信息异常

以上两点错误请对应的看报错信息里的图1和图2

报错信息

错误1:
Concurrent = false 串行模式下JobMonitor的OnExecutedAsync中的获取当前context.Trigger.ElapsedTime时间异常
image

错误2:
Concurrent = true下除上述的context.Trigger.ElapsedTime时间异常外,日志信息输出线程安全异常
image

疑问和建议

以上还只是一个Job的情况,如果是多个Job共用该全局的JobMonitor情况类似,该怎么通用的保证每个Job的执行前后输出信息且保证线程安全和每个job的执行时间统计上线程安全?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.