Не отвечайте на запрос GET мгновенно, это ответ, когда тикер сделан - PullRequest
0 голосов
/ 11 мая 2018

Я новичок в программировании на Go и пытаюсь создать API для многопользовательской игры.Если я сделаю GET req к http://localhost:8080/create_game/gameName.Ответ сервера на запрос по завершении тикера.Мне нужно получить ответ от сервера мгновенно, но я получил его, когда тикер закончен, а игра отсчитана и удалена.

Вот мой код:

var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Game)

//GAME_TIMEOUT in seconds
const GAME_TIMEOUT = 20

//ID generating
var genID = 0

var games = []Game{}

var msg json.RawMessage

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

type GameToSend struct {
    Type string `json:"type"`
    ID   int    `json:"id"`
    Name string `json:"name"`
}
type Game struct {
    ID    int              `json:"id"`
    Name  string           `json:"name"`
    Timer <-chan time.Time `json:"timestamp"`
}

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/create_game/{name}", createGame)
    router.HandleFunc("/game_events", handleConnections)
    http.ListenAndServe(":8080", router)
}

func handleConnections(w http.ResponseWriter, r *http.Request) {

    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    clients[conn] = true
    for _, game := range games {
        conn.WriteJSON(GameToSend{"game.created", game.ID, game.Name})
    }
    for {
        err := conn.ReadJSON(&msg)
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Println(msg)
        }
    }
}

func broadcastGame(game GameToSend) {
    for conn := range clients {
        conn.WriteJSON(game)
    }
}

func createGame(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    genID++
    game := Game{genID, params["name"], time.NewTimer(GAME_TIMEOUT * time.Second).C}
    games = append(games, game)
    broadcastGame(GameToSend{"game.created", game.ID, game.Name})
    w.Write([]byte("response"))
    checkTimeout(genID)
}

func deleteGame(actionType string, i int) {
    for index, game := range games {
        if game.ID == i {
            broadcastGame(GameToSend{actionType, games[index].ID, games[index].Name})
            games = games[:index+copy(games[index:], games[index+1:])]
        }
    }
}

func checkTimeout(id int) {
    for _, game := range games {
        if game.ID == id {
            <-game.Timer
            deleteGame("game.timeout", id)
        }
    }
}

есть идеи как это исправить?

1 Ответ

0 голосов
/ 11 мая 2018

Есть несколько вещей, которые вы можете изменить, но одна из них, как правило, заключается в том, чтобы не запускать потенциально долго выполняющиеся задачи в коде, который отвечает клиентам.Представьте, что у вас миллионы игр, так много, что каждый вызов checkTimeout занимает секунду, чтобы перебрать все игры.Каждый запрос будет иметь задержку в одну секунду, чтобы получить полный ответ, не очень.Было бы лучше дать понять, что другая программа должна выполнить итерации по играм и очистить устаревшие, чтобы вы могли немедленно вернуться к клиенту, пока очистка происходит в фоновом режиме.

Оказывается, я неправильно понял, кто выделаю, но совет остается в силе.В этом случае, хотя «длительная функция» фактически ждет, пока таймер истекает, прежде чем вернуться.Это может быть значительно дольше, чем одна секунда!Вы хотели запустить это в рутину?go checkTimeout(genID)

...