/* 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."))
	}
}
Example #2
0
//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))
		}
	}
}