/* Should contain a form value dbname which equals the database name e.g. curl www.hostname.com/backup/now -X POST -d "dbname=nameofdatabase" The {how} should be either "now" or "enqueue" */ func BackupHandler(w http.ResponseWriter, request *http.Request) { vars := mux.Vars(request) dbname := request.FormValue("dbname") t := tasks.NewTask() t.Action = "BackupDatabase" t.Data = dbname t.Node = globals.MyIP t.Role = globals.ServiceRole t.TTL = 3600 t.ClusterService = globals.ClusterService t.NodeType = "read" if consul.IsWriteNode(globals.MyIP) { t.NodeType = "write" } var err error if dbname != "rdpg" { //Using FindByDatabase to determine if the database actually exists to be backed up. inst, err := instances.FindByDatabase(dbname) if err != nil { log.Error(fmt.Sprintf("admin.BackupHandler() instances.FindByDatabase(%s) Error occurred when searching for database.", dbname)) w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Error encountered while searching for database")) return } if inst == nil { //...then the database doesn't exist on this cluster. log.Debug(fmt.Sprintf("admin.BackupHandler() Attempt to initiate backup on non-existant database with name: %s", dbname)) w.WriteHeader(http.StatusNotFound) w.Write([]byte("Database not found")) return } } switch vars[`how`] { //Immediately calls Backup() and performs the backup case "now": err = t.BackupDatabase() if err != nil { log.Error(fmt.Sprintf(`api.BackupHandler() Task.BackupDatabase() %+v ! %s`, t, err)) w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Error encountered while trying to perform backup")) return } w.Write([]byte("Backup completed.")) case "enqueue": // Queues up a backup to be done with a worker thread gets around to it. // This call returns after the queuing process is done; not after the backup is done. err = t.Enqueue() if err != nil { log.Error(fmt.Sprintf(`api.BackupHandler() Task.Enqueue() %+v ! %s`, t, err)) w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Error while trying to queue")) return } w.Write([]byte("Backup successfully queued.")) } }
//Work - Select a task from the queue for this server func Work() { err := OpenWorkDB() if err != nil { log.Error(fmt.Sprintf("tasks.Work() OpenWorkDB() %s", err)) proc, _ := os.FindProcess(os.Getpid()) proc.Signal(syscall.SIGTERM) } err = OpenWorkDB() if err != nil { log.Error(fmt.Sprintf("tasks.Work() OpenWorkDB() %s", err)) proc, _ := os.FindProcess(os.Getpid()) proc.Signal(syscall.SIGTERM) } defer CloseWorkDB() for { tasks := []Task{} err = WorkLock() if err != nil { time.Sleep(10 * time.Second) continue } nodeType := `read` if consul.IsWriteNode(globals.MyIP) { nodeType = `write` } sq := fmt.Sprintf(`SELECT id,cluster_id,node,role,action,data,ttl,node_type,cluster_service FROM tasks.tasks WHERE locked_by IS NULL AND role IN ('all','%s') AND node IN ('*','%s') AND node_type IN ('any','%s') ORDER BY created_at DESC LIMIT 1`, globals.ServiceRole, globals.MyIP, nodeType) log.Trace(fmt.Sprintf(`tasks.Work() > %s`, sq)) err = workDB.Select(&tasks, sq) if err != nil { WorkUnlock() if err == sql.ErrNoRows { log.Trace(`tasks.Work() No tasks found.`) } else { log.Error(fmt.Sprintf(`tasks.Work() Selecting Task ! %s`, err)) } time.Sleep(5 * time.Second) continue } if len(tasks) == 0 { WorkUnlock() time.Sleep(5 * time.Second) continue } task := tasks[0] err = task.Dequeue() if err != nil { log.Error(fmt.Sprintf(`tasks.Work() Task<%d>#Dequeue() ! %s`, task.ID, err)) continue } WorkUnlock() // TODO: Come back and have a cleanup routine for tasks that were locked // but never finished past the TTL, perhaps a health check or such. err = task.Work() if err != nil { log.Error(fmt.Sprintf(`tasks.Task<%d>#Work() ! %s`, task.ID, err)) sq = fmt.Sprintf(`UPDATE tasks.tasks SET locked_by=NULL, processing_at=NULL WHERE id=%d`, task.ID) log.Trace(fmt.Sprintf(`tasks#Work() > %s`, sq)) _, err = workDB.Exec(sq) if err != nil { log.Error(fmt.Sprintf(`tasks.Work() Updating Task %d processing_at ! %s`, task.ID, err)) } continue } else { // TODO: (t *Task) Delete() sq = fmt.Sprintf(`DELETE FROM tasks.tasks WHERE id=%d`, task.ID) log.Trace(fmt.Sprintf(`tasks#Work() > %s`, sq)) _, err = workDB.Exec(sq) if err != nil { log.Error(fmt.Sprintf(`tasks.Work() Deleting Task %d ! %s`, task.ID, err)) continue } log.Trace(fmt.Sprintf(`tasks.Work() Task Completed! > %+v`, task)) } } }