
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 contextudalost 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.