Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
DMCKirito opened this issue Nov 12, 2023 · 4 comments
Labels
enhancement New feature or request

Comments

@DMCKirito
Copy link

DMCKirito commented Nov 12, 2023

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
Copy link

holmofy commented Aug 2, 2024

fix delay vs. fix rate.

@mvniekerk
Copy link
Owner

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

@mvniekerk mvniekerk added the enhancement New feature or request label Aug 9, 2024
@DMCKirito
Copy link
Author

fix delay vs. fix rate.

Yes, that's what I want to express.

@DMCKirito
Copy link
Author

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 next_tick and now. What I need is a fixed delay mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants