diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/calendar-sync-source.el | 15 | ||||
| -rw-r--r-- | modules/calendar-sync.el | 18 |
2 files changed, 28 insertions, 5 deletions
diff --git a/modules/calendar-sync-source.el b/modules/calendar-sync-source.el index d9efc885b..15c91c594 100644 --- a/modules/calendar-sync-source.el +++ b/modules/calendar-sync-source.el @@ -90,7 +90,13 @@ Hash table mapping calendar name (string) to state plist with: (let ((cal-states (alist-get 'calendar-states state))) (clrhash calendar-sync--calendar-states) (dolist (entry cal-states) - (puthash (car entry) (cdr entry) calendar-sync--calendar-states))))) + (let ((st (cdr entry))) + ;; A persisted `syncing' status is stale in a fresh process + ;; (no sync is actually running), so reset it; otherwise the + ;; in-flight guard would skip that calendar forever. + (when (eq (plist-get st :status) 'syncing) + (setq st (plist-put (copy-sequence st) :status 'never))) + (puthash (car entry) st calendar-sync--calendar-states)))))) (error (calendar-sync--log-silently "calendar-sync: Error loading state: %s" (error-message-string err)))))) @@ -98,6 +104,13 @@ Hash table mapping calendar name (string) to state plist with: "Get state plist for CALENDAR-NAME, or nil if not found." (gethash calendar-name calendar-sync--calendar-states)) +(defun calendar-sync--syncing-p (calendar-name) + "Return non-nil when CALENDAR-NAME has an in-flight sync. +Used to skip an overlapping sync when a timer tick fires while the previous +sync for the same calendar is still running." + (eq (plist-get (calendar-sync--get-calendar-state calendar-name) :status) + 'syncing)) + (defun calendar-sync--set-calendar-state (calendar-name state) "Set STATE plist for CALENDAR-NAME." (puthash calendar-name state calendar-sync--calendar-states)) diff --git a/modules/calendar-sync.el b/modules/calendar-sync.el index 297d1fe61..804d71faf 100644 --- a/modules/calendar-sync.el +++ b/modules/calendar-sync.el @@ -211,10 +211,20 @@ fetcher) or :account + :calendar-id (the \\='api fetcher). Dispatches on the :fetcher key, defaulting to the .ics path. Updates calendar state and saves to disk on completion. The fetch and conversion run in external processes so parsing and writing large -calendar files do not block the interactive Emacs thread." - (if (eq (plist-get calendar :fetcher) 'api) - (calendar-sync--sync-calendar-api calendar) - (calendar-sync--sync-calendar-ics calendar))) +calendar files do not block the interactive Emacs thread. + +Skips a calendar whose previous sync is still in flight, so a timer tick that +fires before a slow fetch finishes does not launch a second overlapping sync for +the same calendar." + (let ((name (plist-get calendar :name))) + (cond + ((calendar-sync--syncing-p name) + (calendar-sync--log-silently + "calendar-sync: [%s] sync already in flight; skipping overlapping tick" name)) + ((eq (plist-get calendar :fetcher) 'api) + (calendar-sync--sync-calendar-api calendar)) + (t + (calendar-sync--sync-calendar-ics calendar))))) (defun calendar-sync--require-calendars () "Return non-nil if calendars are configured, else warn and return nil." |
