Short and Long Polling with implementation in Golang

Rahul Kapoor
3 min readNov 6, 2023

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
}

--

--