NodeJS HTTP server
Tohle vsichni znate: HTTP server tim nejjednodussim zpusobem, jak to v NodeJS napsat. Kdyz teda opominu nejake skopiciny, ktera jsem do kodu doplnil, abych simuloval zatez na serveru aspon nejakym nahodne generovanym delayem a globalni pocitadlo pripojenych, obsluhovanych requestu:
const http = require("http"); const port = process.env.PORT || 8080; function hardWorker(req, res, workerId, sleepTime, cb) { setTimeout(() =>; { res.end(`hello no ${workerId} from server\n`); cb(); }, sleepTime * 1000); } let numOfWorkers = 0; const server = http.createServer((req, res) => { const workerId = ++numOfWorkers; const sleepTime = Math.floor(Math.random() * (10 - 3 + 1) + 3) console.log(`welcome! ${workerId} (${sleepTime}s)`); hardWorker(req, res, workerId, sleepTime, () => { console.log(`done ${workerId}`); }); }); server.listen(port, () => { console.log(`server is running: http://localhost:${port}`); });
Vysledek ja jasny a ocekavatelny. Na server prijde request, ten spusti handler s obsluhou, v mem pripade jen pocka N sekund a pak vrati klientovi odpoved:
Posles request, server je prijme a zacne zpracovavat, klient ceka na dokonceni zpracovani. Az ma server vysledek, posle jej na klienta a ten jej prijme. Konec requestu.
No jo! Co kdyz ale vybavovani requestu trva dele nez je klientovi libo?
A ten se rozhodne proste request cancelovat…. Klient je v pohode. Proste zrusi cekani na response a jde delat neco jineho. Ale na serveru se nic nemeni. Ten dal provadi obsluhy requestu, aby jej na konci zahodil….
A to neni neco, co byste chteli…
Predstavte si, ze mate API server, ktery je bezne vystavovan vysoke zatezi nejake webove aplikaci, ktere poskytuje nejkou backendovou funkcionalitu. V pripade divokeho posilani requestu se teoreticky docela jednoduse muzete dostat do situace, kdy k serveru uz neni nikod pripojeny, ale na serveru bezi treba i tisicovka procesu nastartovanych prochozimi requesty.
A je jasne, ze request muze konzumovat dalsi prostredky, jako je treba databazova konektivita a podobne…
A jeste vetsi je to sranda, pokud svou backend bezite v nejate te cloudove sluzbe a kazdy novy request vam treba spusti jejakou tu serveless funkci, nebo ja nevim co a zacne vam to uzirat penize z budgetu, aniz byste cokoliv dorucily klientovi….
Uplne idelani by bylo, kdyby server poznal, ze klient zahodil request a sam zrusil vse co s tim souvisi…
To zni i docela logicky a ocekavatelne. Ne? Ale presne tohle v NodeJS nejde. Jeho HTTP modul se chova presne tak, jak jsem popsal vyse. Proste s kazdym requestem nastartuje jeho zpracovani a maka tak dlouho, dokud jej kompletne nevyridi.
Heja! A presne tohle umi Golang 🙂
Go od verze 1.12 ma
coz je presne to co potrebujete. Context je prostredi, ktere vam mimo jine umi zprostredkovat prave context
udalost v ramci vaseho zpracovani.cancel
Je to presne ten nastroj, ktery potrebujete k tomu, abyste na serveru dokazali vypropagovat zruseni obsluhy zpracovani requestu do vsech mist kodu, kde by se vam to mohlo hodit, nenbo kde to potrebujete.
Jinymi slovy: ano Go umi to, ze v pripade, ze klient zahodi, zrusi pripojeni, zastavi na serveru jeho zpracovani.
Genialni!
Je to presne to, co na serveru chcete. Nemrhat prostredky a pracovat efektivne jen kdyz je to potreba.
Server v Go pak muze vypadat takto
package main import ( "fmt" "math/rand" "net/http" "os" "time" ) var numOfWorkers = 0 func hardWorker(w http.ResponseWriter, r *http.Request) { numOfWorkers++ workerID := numOfWorkers sleepTime := rand.Intn(10-3) + 3 ctx := r.Context() fmt.Printf("welcome! %d (%ds)\n", workerID, sleepTime) select { case <-time.After(time.Duration(sleepTime) * time.Second): w.Write([]byte(fmt.Sprintf("hello no %d from server\n", workerID))) fmt.Printf("done %d\n", workerID) case <-ctx.Done(): fmt.Println(fmt.Sprintf("oups! request %d cancelled\n", workerID)) } } func main() { var port string if port = os.Getenv("PORT"); port == "" { port = "8081" } rand.Seed(time.Now().UTC().UnixNano()) fmt.Println("server is running: http://localhost:" + port) http.ListenAndServe(":"+port, http.HandlerFunc(hardWorker)) }
Co z toho vyplyva?
Je jedno v cem pisete sve serverove aplikace. Meli byste ale vzdy premyslet o tom, jak veci skutecne funguji. Muze se vam to hodit.