Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang: Shared communication in async http server

Tags:

go

Absolute beginner to golang other than writing a simple http server. I'm researching Go as a possibility for writing an async process. If you could please provide a quick sample of how this might be accomplished:

Http request 'a' comes in, an operation is started based on POST payload in this request (with some sort of unique identifier in post or url). The async process started by 'a' will respond back to same server with original unique identifier (request 'b') while request 'a' is still open. I'd like to communicate that response back to request 'a' based on request 'b' response.

like image 379
kwolfe Avatar asked Jan 18 '26 16:01

kwolfe


1 Answers

Although it is possible to do this with channels, I would prefer a hash (map) that is protected by a mutex, since it is easier in this case.

To give you an idea and get you going:

package main

import (
    "fmt"
    "net/http"
    "sync"
)

type state struct {
    *sync.Mutex // inherits locking methods
    Vals map[string]string // map ids to values
}

var State = &state{&sync.Mutex{}, map[string]string{}}

func get(rw http.ResponseWriter, req *http.Request) {
    State.Lock()
    defer State.Unlock() // ensure the lock is removed after leaving the the function
    id := req.URL.Query().Get("id") // if you need other types, take a look at strconv package
    val := State.Vals[id]
    delete(State.Vals, id)
    rw.Write([]byte("got: " + val))
}

func post(rw http.ResponseWriter, req *http.Request) {
    State.Lock()
    defer State.Unlock()
    id := req.FormValue("id")
    State.Vals[id] = req.FormValue("val")
    rw.Write([]byte("go to http://localhost:8080/?id=42"))
}

var form = `<html>
    <body>
        <form action="/" method="POST">
            ID: <input name="id" value="42" /><br />
            Val: <input name="val" /><br />
            <input type="submit" value="submit"/>
        </form>
    </body>
</html>`

func formHandler(rw http.ResponseWriter, req *http.Request) {
    rw.Write([]byte(form))
}

// for real routing take a look at gorilla/mux package
func handler(rw http.ResponseWriter, req *http.Request) {
    switch req.Method {
    case "POST":
        post(rw, req)
    case "GET":
        if req.URL.String() == "/form" {
            formHandler(rw, req)
            return
        }
        get(rw, req)
    }
}

func main() {
    fmt.Println("go to http://localhost:8080/form")
    // thats the default webserver of the net/http package, but you may
    // create custom servers as well
    err := http.ListenAndServe("localhost:8080", http.HandlerFunc(handler))
    if err != nil {
        fmt.Println(err)
    }
}
like image 150
metakeule Avatar answered Jan 20 '26 21:01

metakeule