Short and Long Polling with implementation in Golang
Short Polling
We have to send multiple connections from the client to the server to check if the server has successfully processed our request.
A lot of connections made will be made and responded with Nothing to respond, so this doesn't seem to be highly scalable with large number of daily active users.
Hence the client keeps making the HTTP requests at a regular interval for example every 1–2 seconds. In this case, most of the requests might get an empty response because the server might not have any updates which are useful for the client.
Sample Implementation in Golang
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/mux"
)
var job = make(map[string]int)
func updateJob(jobId string, prog int) {
job[jobId] = prog
fmt.Println("updated job with progress: ", job[jobId])
if prog == 100 {
return
}
time.AfterFunc(3*time.Second, func() {
updateJob(jobId, prog+10)
})
}
func checkStatus(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
jobId := params["id"]
fmt.Println("Checking status of job with jobid: ", jobId)
fmt.Println("status of job is: ", job[jobId])
json.NewEncoder(w).Encode(job[jobId])
}
func postdata(w http.ResponseWriter, r *http.Request) {
currJob := "job:" + time.Now().Format("20231125")
//add this currjob to map with progress init to 0
job[currJob] = 0
fmt.Println(currJob)
updateJob(currJob, 0)
json.NewEncoder(w).Encode(currJob)
}
func handleRequests() {
r := mux.NewRouter()
r.HandleFunc("/status/{id}", checkStatus).Methods("GET")
r.HandleFunc("/post", postdata).Methods("POST")
log.Fatal(http.ListenAndServe(":8000", r))
}
func main() {
handleRequests()
return
}
Long Polling
Long polling will create a connection between client-server and keep on waiting till we get a response or get a timeout.
Sample Implementation in Golang
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"sync"
"time"
"github.com/gorilla/mux"
)
var job = make(map[string]int)
//need to take lock while updating the map with jobID to avoid concurrent read + write
var mut sync.Mutex
func updateJob(jobId string, prog int) {
mut.Lock()
job[jobId] = prog
mut.Unlock()
fmt.Println("updated job with progress: ", job[jobId])
if prog == 100 {
return
}
time.AfterFunc(3*time.Second, func() {
updateJob(jobId, prog+20)
})
}
func checkStatus(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
jobId := params["id"]
fmt.Println("Checking status of job with jobid: ", jobId)
fmt.Println("status of job is: ", job[jobId])
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
if job[jobId] >= 100 {
break
}
}
}()
wg.Wait()
json.NewEncoder(w).Encode(job[jobId])
}
func postdata(w http.ResponseWriter, r *http.Request) {
currJob := "job:" + time.Now().Format("20231125")
//add this currjob to map with progress init to 0
job[currJob] = 0
fmt.Println(currJob)
updateJob(currJob, 0)
json.NewEncoder(w).Encode(currJob)
}
func handleRequests() {
r := mux.NewRouter()
r.HandleFunc("/status/{id}", checkStatus).Methods("GET")
r.HandleFunc("/post", postdata).Methods("POST")
log.Fatal(http.ListenAndServe(":8000", r))
}
func main() {
handleRequests()
return
}