mvniekerk / tokio-cron-scheduler

Schedule tasks on Tokio using cron-like annotation
Apache License 2.0
529 stars 59 forks source link

Handling Cases in repeated_async Jobs Where Execution Time Exceeds Interval Time #56

Open DMCKirito opened 1 year ago

DMCKirito commented 1 year ago

Hello,

I am currently working with a repeated_async type job in my project, where the job runs at an interval of 2 seconds. In most cases, it functions as expected. However, I've encountered a scenario where certain I/O operations, such as an unexpected MySQL connection timeout, cause a significant delay. This delay results in subsequent tasks being unable to execute.

Upon reviewing the source code, I noticed that the next_tick is always incremented based on the previous execution time (always moving from 11:05:31 -> 11:05:33 -> 11:05:35, for example), whereas the last_tick represents the time when the current task completes. This behavior seems to lead to a situation where, if a task takes longer than the job's interval, subsequent jobs are never executed.

let next_and_last_tick = match job {
      Ok(Some(job)) => {
          let job_type: JobType = JobType::from_i32(job.job_type).unwrap();
          let schedule = job.schedule();
          let repeated_every = job.repeated_every();
          let next_tick = job.next_tick_utc();
          let next_tick = match job_type {
              JobType::Cron => schedule.and_then(|s| s.after(&now).next()),
              JobType::OneShot => None,
              JobType::Repeated => repeated_every.and_then(|r| {
                  next_tick.and_then(|nt| {
                      nt.checked_add_signed(chrono::Duration::seconds(
                          r as i64,
                      ))
                  })
              }),
          };
          let last_tick = Some(now);
          Some((next_tick, last_tick))
      }
      _ => {
          error!("Could not get job metadata");
          None
      }

What I am looking for is a behavior more akin to a loop with a sleep mechanism, where, regardless of how long a job takes to execute, the next job would still run after the fixed interval. Is there any consideration for adding such a job type?

Thank you for your attention to this matter.

holmofy commented 3 months ago

fix delay vs. fix rate.

mvniekerk commented 3 months ago

Hi @DMCKirito , thank you for the report. Some sort of backpressure handling thus? Could be a cool extra feature

DMCKirito commented 3 months ago

fix delay vs. fix rate.

Yes, that's what I want to express.

DMCKirito commented 3 months ago

Hi @DMCKirito , thank you for the report. Some sort of backpressure handling thus? Could be a cool extra feature

I want to provide an additional detail to my question. I discovered that the root cause of the issue is due to using actix_web with its single-threaded model, which causes tasks submitted in jobs to run on the main thread. Sometimes, I submit an I/O-blocking task on the main thread, which leads to issues with comparing _nexttick and now. What I need is a fixed delay mode.