Sobes.tech
Back to questions
Middle
4

// Описание: // Нужно реализовать backend часть приложения планировщика, в котором будет 3 метода: // 1) Создать команду с ID и временем запуска. // 2) Получить список активных команд. // 3) Отменить команду по ID. // Команда должна выполнится точно в переданное в первом методе // Методы будут вызываться через HTTP сервер, количество одновременных запросов // этих методов не определено // Само выполнение команды пускай будет Print(ID) в stdout, чтобы эмулировать выполнение.

Companies where asked
Бюро 1440Бюро 1440

Answer from AI

sobes.tech AI

Для реализации backend части планировщика с тремя методами на Go можно использовать HTTP сервер с обработчиками для создания, получения и отмены команд. Для точного выполнения команды в заданное время удобно использовать таймеры или планировщик задач.

Основные моменты:

  • Хранить команды в потокобезопасной структуре (например, sync.Map или с мьютексом).
  • При создании команды запускать таймер, который сработает в нужное время и выведет ID.
  • Метод получения активных команд возвращает список команд, которые ещё не выполнены и не отменены.
  • Метод отмены команды удаляет её из хранилища и отменяет таймер.

Пример упрощённой реализации:

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"
)

type Command struct {
	ID       string    `json:"id"`
	ExecTime time.Time `json:"exec_time"`
	timer    *time.Timer
}

var (
	commands = make(map[string]*Command)
	mu       sync.Mutex
)

func createCommand(w http.ResponseWriter, r *http.Request) {
	var cmd Command
	if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
		http.Error(w, "Invalid input", http.StatusBadRequest)
		return
	}

	mu.Lock()
	defer mu.Unlock()

	if _, exists := commands[cmd.ID]; exists {
		http.Error(w, "Command already exists", http.StatusBadRequest)
		return
	}

	dur := time.Until(cmd.ExecTime)
	if dur <= 0 {
		http.Error(w, "ExecTime must be in the future", http.StatusBadRequest)
		return
	}

	cmd.timer = time.AfterFunc(dur, func() {
		fmt.Println(cmd.ID)
		mu.Lock()
		delete(commands, cmd.ID)
		mu.Unlock()
	})

	commands[cmd.ID] = &cmd
	w.WriteHeader(http.StatusCreated)
}

func listCommands(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	defer mu.Unlock()

	active := make([]Command, 0, len(commands))
	for _, cmd := range commands {
		active = append(active, Command{ID: cmd.ID, ExecTime: cmd.ExecTime})
	}

	json.NewEncoder(w).Encode(active)
}

func cancelCommand(w http.ResponseWriter, r *http.Request) {
	id := r.URL.Query().Get("id")
	if id == "" {
		http.Error(w, "Missing id parameter", http.StatusBadRequest)
		return
	}

	mu.Lock()
	defer mu.Unlock()

	cmd, exists := commands[id]
	if !exists {
		http.Error(w, "Command not found", http.StatusNotFound)
		return
	}

	cmd.timer.Stop()
	delete(commands, id)
	w.WriteHeader(http.StatusOK)
}

func main() {
	http.HandleFunc("/create", createCommand)
	http.HandleFunc("/list", listCommands)
	http.HandleFunc("/cancel", cancelCommand)

	log.Println("Server started on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Такой подход обеспечивает точное выполнение команд в заданное время, потокобезопасность и возможность отмены.