From a2baa1546f0c270545fee2e661c5bd13be837c3b Mon Sep 17 00:00:00 2001
From: Cam Saul <cammsaul@gmail.com>
Date: Mon, 9 Jul 2018 16:46:13 -0700
Subject: [PATCH] Don't barf if task has already been scheduled

---
 src/metabase/task.clj                |  5 ++++-
 src/metabase/task/send_pulses.clj    | 23 +++++++++++------------
 src/metabase/task/sync_databases.clj | 22 +++++++++++-----------
 3 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/src/metabase/task.clj b/src/metabase/task.clj
index c710cd8e5c2..f3e475749d4 100644
--- a/src/metabase/task.clj
+++ b/src/metabase/task.clj
@@ -99,7 +99,10 @@
   "Add a given job and trigger to our scheduler."
   [job :- JobDetail, trigger :- Trigger]
   (when-let [scheduler (scheduler)]
-    (qs/schedule scheduler job trigger)))
+    (try
+      (qs/schedule scheduler job trigger)
+      (catch org.quartz.ObjectAlreadyExistsException _
+        (log/info (trs "Job already exists:") (-> job .getKey .getName))))))
 
 (s/defn delete-task!
   "delete a task from the scheduler"
diff --git a/src/metabase/task/send_pulses.clj b/src/metabase/task/send_pulses.clj
index b8765ce3c77..8c12234cace 100644
--- a/src/metabase/task/send_pulses.clj
+++ b/src/metabase/task/send_pulses.clj
@@ -63,26 +63,25 @@
   []
   ;; build our job
   (reset! send-pulses-job (jobs/build
-                               (jobs/of-type SendPulses)
-                               (jobs/with-identity (jobs/key send-pulses-job-key))))
+                           (jobs/of-type SendPulses)
+                           (jobs/with-identity (jobs/key send-pulses-job-key))))
   ;; build our trigger
   (reset! send-pulses-trigger (triggers/build
-                                   (triggers/with-identity (triggers/key send-pulses-trigger-key))
-                                   (triggers/start-now)
-                                   (triggers/with-schedule
-                                     ;; run at the top of every hour
-                                     (cron/cron-schedule "0 0 * * * ? *"))))
+                               (triggers/with-identity (triggers/key send-pulses-trigger-key))
+                               (triggers/start-now)
+                               (triggers/with-schedule
+                                 ;; run at the top of every hour
+                                 (cron/cron-schedule "0 0 * * * ? *"))))
   ;; submit ourselves to the scheduler
   (task/schedule-task! @send-pulses-job @send-pulses-trigger))
 
 
-;;; ## ---------------------------------------- PULSE SENDING ----------------------------------------
-
+;;; ------------------------------------------------- PULSE SENDING --------------------------------------------------
 
 (defn- send-pulses!
-  "Send any `Pulses` which are scheduled to run in the current day/hour.  We use the current time and determine the
-   hour of the day and day of the week according to the defined reporting timezone, or UTC.  We then find all `Pulses`
-   that are scheduled to run and send them."
+  "Send any `Pulses` which are scheduled to run in the current day/hour. We use the current time and determine the hour
+  of the day and day of the week according to the defined reporting timezone, or UTC. We then find all `Pulses` that
+  are scheduled to run and send them."
   [hour weekday monthday monthweek]
   {:pre [(integer? hour)
          (and (<= 0 hour) (>= 23 hour))
diff --git a/src/metabase/task/sync_databases.clj b/src/metabase/task/sync_databases.clj
index 3c1394e53f0..234ec36cd48 100644
--- a/src/metabase/task/sync_databases.clj
+++ b/src/metabase/task/sync_databases.clj
@@ -25,7 +25,7 @@
 ;;; +----------------------------------------------------------------------------------------------------------------+
 
 (s/defn ^:private job-context->database :- DatabaseInstance
-  "Get the Database referred to in JOB-CONTEXT. Guaranteed to return a valid Database."
+  "Get the Database referred to in `job-context`. Guaranteed to return a valid Database."
   [job-context]
   (Database (u/get-id (get (qc/from-job-data job-context) "db-id"))))
 
@@ -68,27 +68,27 @@
 ;; using them
 
 (s/defn ^:private job-key :- JobKey
-  "Return an appropriate string key for the job described by TASK-INFO for DATABASE-OR-ID."
+  "Return an appropriate string key for the job described by `task-info` for `database-or-id`."
   [task-info :- TaskInfo]
   (jobs/key (format "metabase.task.%s.job" (name (:key task-info)))))
 
 (s/defn ^:private trigger-key :- TriggerKey
-  "Return an appropriate string key for the trigger for TASK-INFO and DATABASE-OR-ID."
+  "Return an appropriate string key for the trigger for `task-info` and `database-or-id`."
   [database :- DatabaseInstance, task-info :- TaskInfo]
   (triggers/key (format "metabase.task.%s.trigger.%d" (name (:key task-info)) (u/get-id database))))
 
 (s/defn ^:private cron-schedule :- cron-util/CronScheduleString
-  "Fetch the appropriate cron schedule string for DATABASE and TASK-INFO."
+  "Fetch the appropriate cron schedule string for `database` and `task-info`."
   [database :- DatabaseInstance, task-info :- TaskInfo]
   (get database (:db-schedule-column task-info)))
 
 (s/defn ^:private job-class :- Class
-  "Get the Job class for TASK-INFO."
+  "Get the Job class for `task-info`."
   [task-info :- TaskInfo]
   (:job-class task-info))
 
 (s/defn ^:private trigger-description :- s/Str
-  "Return an appropriate description string for a job/trigger for Database described by TASK-INFO."
+  "Return an appropriate description string for a job/trigger for Database described by `task-info`."
   [database :- DatabaseInstance, task-info :- TaskInfo]
   (format "%s Database %d" (name (:key task-info)) (u/get-id database)))
 
@@ -103,7 +103,7 @@
 ;;; +----------------------------------------------------------------------------------------------------------------+
 
 (s/defn ^:private delete-task!
-  "Cancel a single sync task for DATABASE-OR-ID and TASK-INFO."
+  "Cancel a single sync task for `database-or-id` and `task-info`."
   [database :- DatabaseInstance, task-info :- TaskInfo]
   (let [trigger-key (trigger-key database task-info)]
     (log/debug (u/format-color 'red "Unscheduling task for Database %d: trigger: %s"
@@ -111,7 +111,7 @@
     (task/delete-trigger! trigger-key)))
 
 (s/defn unschedule-tasks-for-db!
-  "Cancel *all* scheduled sync and FieldValues caching tassks for DATABASE-OR-ID."
+  "Cancel *all* scheduled sync and FieldValues caching tasks for `database-or-id`."
   [database :- DatabaseInstance]
   (delete-task! database sync-analyze-task-info)
   (delete-task! database field-values-task-info))
@@ -122,7 +122,7 @@
 ;;; +----------------------------------------------------------------------------------------------------------------+
 
 (s/defn ^:private job :- JobDetail
-  "Build a durable Quartz Job for TASK-INFO. Durable in Quartz allows the job to exist even if there are no triggers
+  "Build a durable Quartz Job for `task-info`. Durable in Quartz allows the job to exist even if there are no triggers
   for it."
   [task-info :- TaskInfo]
   (jobs/build
@@ -135,7 +135,7 @@
 (s/def ^:private field-values-job (job field-values-task-info))
 
 (s/defn ^:private trigger :- CronTrigger
-  "Build a Quartz Trigger for DATABASE and TASK-INFO."
+  "Build a Quartz Trigger for `database` and `task-info`."
   [database :- DatabaseInstance, task-info :- TaskInfo]
   (triggers/build
    (triggers/with-description (trigger-description database task-info))
@@ -153,7 +153,7 @@
       (cron/with-misfire-handling-instruction-fire-and-proceed)))))
 
 (s/defn ^:private schedule-tasks-for-db!
-  "Schedule a new Quartz job for DATABASE and TASK-INFO."
+  "Schedule a new Quartz job for `database` and `task-info`."
   [database :- DatabaseInstance]
   (let [sync-trigger (trigger database sync-analyze-task-info)
         fv-trigger   (trigger database field-values-task-info)]
-- 
GitLab