public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup] server/jobstate: add 'updatd' to Finish variant
Date: Mon, 19 Apr 2021 10:32:16 +0200	[thread overview]
Message-ID: <20210419083216.19096-1-d.csapak@proxmox.com> (raw)

when a user updates a job schedule, we want to save that point in time
to calculate future runs, otherwise when a user updates a schedule to
a time that would have been between the last run and 'now' the
schedule is triggered instantly

for example:
schedule 08:00
last run today 08:00
now it is 12:00

before this patch:
update schedule to 11:00
 -> triggered instantly since we calculate from 08:00

after this patch:
update schedule to 11:00
 -> triggered tomorrow 11:00 since we calculate from today 12:00

the change in the enum type is ok, since by default serde does not
error on unknown fields and the new field is optional

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/config/sync.rs            |  5 ++
 src/api2/config/tape_backup_job.rs |  5 ++
 src/api2/config/verify.rs          |  5 ++
 src/server/jobstate.rs             | 82 ++++++++++++++++++++++++------
 4 files changed, 82 insertions(+), 15 deletions(-)

diff --git a/src/api2/config/sync.rs b/src/api2/config/sync.rs
index 00a8c0b3..aa8369fd 100644
--- a/src/api2/config/sync.rs
+++ b/src/api2/config/sync.rs
@@ -333,6 +333,7 @@ pub fn update_sync_job(
     if let Some(remote_store) = remote_store { data.remote_store = remote_store; }
     if let Some(owner) = owner { data.owner = Some(owner); }
 
+    let schedule_changed = data.schedule != schedule;
     if schedule.is_some() { data.schedule = schedule; }
     if remove_vanished.is_some() { data.remove_vanished = remove_vanished; }
 
@@ -344,6 +345,10 @@ pub fn update_sync_job(
 
     sync::save_config(&config)?;
 
+    if schedule_changed {
+        crate::server::jobstate::try_update_state_file("syncjob", &id)?;
+    }
+
     Ok(())
 }
 
diff --git a/src/api2/config/tape_backup_job.rs b/src/api2/config/tape_backup_job.rs
index caea4e18..776b89e4 100644
--- a/src/api2/config/tape_backup_job.rs
+++ b/src/api2/config/tape_backup_job.rs
@@ -266,6 +266,7 @@ pub fn update_tape_backup_job(
     if latest_only.is_some() { data.setup.latest_only = latest_only; }
     if notify_user.is_some() { data.setup.notify_user = notify_user; }
 
+    let schedule_changed = data.schedule != schedule;
     if schedule.is_some() { data.schedule = schedule; }
 
     if let Some(comment) = comment {
@@ -281,6 +282,10 @@ pub fn update_tape_backup_job(
 
     config::tape_job::save_config(&config)?;
 
+    if schedule_changed {
+        crate::server::jobstate::try_update_state_file("tape-backup-job", &id)?;
+    }
+
     Ok(())
 }
 
diff --git a/src/api2/config/verify.rs b/src/api2/config/verify.rs
index db5f4d83..dee4c669 100644
--- a/src/api2/config/verify.rs
+++ b/src/api2/config/verify.rs
@@ -274,12 +274,17 @@ pub fn update_verification_job(
 
     if ignore_verified.is_some() { data.ignore_verified = ignore_verified; }
     if outdated_after.is_some() { data.outdated_after = outdated_after; }
+    let schedule_changed = data.schedule != schedule;
     if schedule.is_some() { data.schedule = schedule; }
 
     config.set_data(&id, "verification", &data)?;
 
     verify::save_config(&config)?;
 
+    if schedule_changed {
+        crate::server::jobstate::try_update_state_file("verificationjob", &id)?;
+    }
+
     Ok(())
 }
 
diff --git a/src/server/jobstate.rs b/src/server/jobstate.rs
index 81e516d4..c62e58a2 100644
--- a/src/server/jobstate.rs
+++ b/src/server/jobstate.rs
@@ -69,8 +69,12 @@ pub enum JobState {
     Created { time: i64 },
     /// The Job was last started in 'upid',
     Started { upid: String },
-    /// The Job was last started in 'upid', which finished with 'state'
-    Finished { upid: String, state: TaskState },
+    /// The Job was last started in 'upid', which finished with 'state', and was last updated at 'updated'
+    Finished {
+        upid: String,
+        state: TaskState,
+        updated: Option<i64>,
+    },
 }
 
 /// Represents a Job and holds the correct lock
@@ -147,12 +151,46 @@ pub fn create_state_file(jobtype: &str, jobname: &str) -> Result<(), Error> {
     job.write_state()
 }
 
+/// Tries to update the state file with the current time
+/// if the job is currently running, does nothing,
+pub fn try_update_state_file(jobtype: &str, jobname: &str) -> Result<(), Error> {
+    let mut job = match Job::new(jobtype, jobname) {
+        Ok(job) => job,
+        Err(_) => return Ok(()), // was locked (running), so do not update
+    };
+    let time = proxmox::tools::time::epoch_i64();
+
+    job.state = match JobState::load(jobtype, jobname)? {
+        JobState::Created { .. } => JobState::Created { time },
+        JobState::Started { .. } => return Ok(()), // currently running (without lock?)
+        JobState::Finished {
+            upid,
+            state,
+            updated: _,
+        } => JobState::Finished {
+            upid,
+            state,
+            updated: Some(time),
+        },
+    };
+    job.write_state()
+}
+
 /// Returns the last run time of a job by reading the statefile
 /// Note that this is not locked
 pub fn last_run_time(jobtype: &str, jobname: &str) -> Result<i64, Error> {
     match JobState::load(jobtype, jobname)? {
         JobState::Created { time } => Ok(time),
-        JobState::Started { upid } | JobState::Finished { upid, .. } => {
+        JobState::Finished {
+            updated: Some(time),
+            ..
+        } => Ok(time),
+        JobState::Started { upid }
+        | JobState::Finished {
+            upid,
+            state: _,
+            updated: None,
+        } => {
             let upid: UPID = upid
                 .parse()
                 .map_err(|err| format_err!("could not parse upid from state: {}", err))?;
@@ -180,7 +218,11 @@ impl JobState {
                         let state = upid_read_status(&parsed)
                             .map_err(|err| format_err!("error reading upid log status: {}", err))?;
 
-                        Ok(JobState::Finished { upid, state })
+                        Ok(JobState::Finished {
+                            upid,
+                            state,
+                            updated: None,
+                        })
                     } else {
                         Ok(JobState::Started { upid })
                     }
@@ -240,7 +282,11 @@ impl Job {
         }
         .to_string();
 
-        self.state = JobState::Finished { upid, state };
+        self.state = JobState::Finished {
+            upid,
+            state,
+            updated: None,
+        };
 
         self.write_state()
     }
@@ -274,17 +320,25 @@ pub fn compute_schedule_status(
     job_state: &JobState,
     schedule: Option<&str>,
 ) -> Result<JobScheduleStatus, Error> {
-
-    let (upid, endtime, state, starttime) = match job_state {
+    let (upid, endtime, state, last) = match job_state {
         JobState::Created { time } => (None, None, None, *time),
         JobState::Started { upid } => {
             let parsed_upid: UPID = upid.parse()?;
             (Some(upid), None, None, parsed_upid.starttime)
-        },
-        JobState::Finished { upid, state } => {
-            let parsed_upid: UPID = upid.parse()?;
-            (Some(upid), Some(state.endtime()), Some(state.to_string()), parsed_upid.starttime)
-        },
+        }
+        JobState::Finished {
+            upid,
+            state,
+            updated,
+        } => {
+            let last = updated.unwrap_or_else(|| state.endtime());
+            (
+                Some(upid),
+                Some(state.endtime()),
+                Some(state.to_string()),
+                last,
+            )
+        }
     };
 
     let mut status = JobScheduleStatus::default();
@@ -292,10 +346,8 @@ pub fn compute_schedule_status(
     status.last_run_state = state;
     status.last_run_endtime = endtime;
 
-    let last = endtime.unwrap_or(starttime);
-
     if let Some(schedule) = schedule {
-        if let Ok(event) =  parse_calendar_event(&schedule) {
+        if let Ok(event) = parse_calendar_event(&schedule) {
             // ignore errors
             status.next_run = compute_next_event(&event, last, false).unwrap_or(None);
         }
-- 
2.20.1





             reply	other threads:[~2021-04-19  8:32 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-19  8:32 Dominik Csapak [this message]
2021-04-19  8:37 ` Dominik Csapak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210419083216.19096-1-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal