Go context zaman aşımları, yavaş veritabanı çağrılarının ve dış isteklerin birikmesini engeller. Deadline iletimi, iptal ve güvenli varsayılanları öğrenin.

context.Context, çağrı zinciriniz boyunca ilettiğiniz küçük bir nesnedir; her katmanın üzerinde anlaşmasını istediğiniz şey şudur: bu isteğin ne zaman durması gerektiği. Zaman aşımları, tek bir yavaş bağımlılığın sunucunuzu meşgul etmesini engellemenin yaygın yoludur.\n\nBir context üç tür bilgi taşıyabilir: bir deadline (işin ne zaman duracağı), bir iptal sinyali (biri işi erken durdurdu) ve birkaç istek kapsamlı değer (bunları seyrek kullanın, büyük veriler için asla kullanmayın).\n\nİptal sihir değildir. Bir context Done() kanalını açığa çıkarır. Kanal kapandığında istek iptal edilmiş ya da süresi dolmuştur. Context'e saygı gösteren kod Done()'ı (select ile sıkça) kontrol eder ve erken döner. Ayrıca ctx.Err() ile neden sona erdiğini öğrenebilirsiniz; genellikle context.Canceled veya context.DeadlineExceeded olur.\n\ncontext.WithTimeout "X saniye sonra dur" için uygundur. Kesin bir kesme zamanınız varsa context.WithDeadline kullanın. Bir ebeveyn koşul işin erken durması gerektiğinde (istemci ayrıldı, kullanıcı başka bir yere gitti, zaten cevabı aldınız) context.WithCancel kullanın.\n\nBir context iptal edildiğinde doğru davranış sıkıcı ama önemlidir: işi durdurun, yavaş I/O'yu beklemeyi bırakın ve net bir hata döndürün. Eğer bir handler veritabanı sorgusunu bekliyorsa ve context sona ererse, hızlıca dönün ve veritabanı çağrısı context destekliyorsa onun abort etmesine izin verin.\n\n## İstek sınırlarını API sınırında koyun\n\nYavaş istekleri durdurmanın en güvenli yeri, trafiğin servisinize girdiği sınırdır. Eğer bir istek zaman aşımına uğrayacaksa, bu işlemin öngörülebilir ve erken olmasını istersiniz; goroutine'lar, DB bağlantıları ve bellek meşgul edildikten sonra değil.\n\nKenar (load balancer, API gateway, reverse proxy) tarafında her isteğin yaşayabileceği maksimum süre için sert bir üst sınır belirleyin. Bu, handler zaman aşımlarını unutsa bile Go servisinizi korur.\n\nGo sunucunuz içinde de HTTP zaman aşımları ayarlayın ki sunucu yavaş bir istemciyi veya takılmış bir yanıtı sonsuza dek beklemesin. En azından başlıkları okuma, tüm istek gövdesini okuma, yanıt yazma ve boşta bekleyen bağlantı süreleri için zaman aşımları yapılandırın.\n\nVarsayılan bir istek bütçesi ürününüze uymalıdır. Birçok API için tipik istekler adına 1–3 saniye makul bir başlangıçtır; dışa aktarmalar gibi bilinen yavaş işlemler için daha yüksek limit tanıyın. Sayıdan çok tutarlılık, ölçme ve istisnalar için net kurallar önemli.\n\nAkış (streaming) yanıtlar ekstra özen ister. Sunucunun bağlantıyı açık tutup küçük parçalar halinde sonsuza dek yazdığı ya da ilk byte'dan önce sonsuza dek beklediği kazara bir sonsuz akış oluşturmak kolaydır. Bir endpoint gerçekten stream değilse, toplam maksimum süre ve ilk byte'a maksimum süre uygulayın.\n\nKenarın net bir deadline'ı olduğunda, bu deadline'ı tüm istek boyunca iletmek çok daha kolay olur.\n\n## Adım adım: bir HTTP handler'a zaman aşımı ekleyin\n\nBaşlamak için en basit yer HTTP handler'dır. Bir istek sisteminize buradan girdiği için sert bir limit koymak doğal bir noktadır.\n\n### 1) Zamanlı bir context türetin\n\nYeni bir context oluşturun ve onu iptal etmeyi unutmayın. Sonra o context'i veritabanı işi, HTTP çağrıları veya yavaş hesaplamalar gibi bloklayabilecek her şeye geçirin.\n\ngo\nfunc (s *Server) GetUser(w http.ResponseWriter, r *http.Request) {\n\tctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)\n\tdefer cancel()\n\n\tuserID := r.URL.Query().Get(\"id\")\n\tif userID == \"\" {\n\t\thttp.Error(w, \"missing id\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tuser, err := s.loadUser(ctx, userID)\n\tif err != nil {\n\t\twriteError(w, ctx, err)\n\t\treturn\n\t}\n\n\twriteJSON(w, http.StatusOK, user)\n}\n\n\n### 2) Her engelleyici çağrıya ctx gönderin\n\nKural: bir fonksiyon I/O üzerinde bekleyebiliyorsa context.Context kabul etmelidir. Handler'ları okunabilir tutmak için detayları loadUser gibi küçük yardımcı fonksiyonlara itebilirsiniz.\n\ngo\nfunc (s *Server) loadUser(ctx context.Context, id string) (User, error) {\n\treturn s.repo.GetUser(ctx, id) // repo should use QueryRowContext/ExecContext\n}\n\n\n### 3) Context sona erdiğinde erken dönün\n\nDeadline dolarsa (veya istemci ayrıldıysa), işi durdurun ve kullanıcı dostu bir yanıt verin. Yaygın bir eşleme context.DeadlineExceeded için 504 Gateway Timeout, context.Canceled için "client is gone" (çoğunlukla gövde olmadan) şeklindedir.\n\ngo\nfunc writeError(w http.ResponseWriter, ctx context.Context, err error) {\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\thttp.Error(w, \"request timed out\", http.StatusGatewayTimeout)\n\t\treturn\n\t}\n\tif errors.Is(err, context.Canceled) {\n\t\t// Client went away. Avoid doing more work.\n\t\treturn\n\t}\n\thttp.Error(w, \"internal error\", http.StatusInternalServerError)\n}\n\n\nBu desen birikmeleri engeller. Zamanlayıcı sona erdiğinde, zincirdeki tüm context-dostu fonksiyonlar aynı durma sinyalini alır ve hızlıca çıkabilir.\n\n## Deadlinelerin PostgreSQL çağrılarına iletilmesi\n\nHandler'ınız bir deadline ile çalışmaya başladıktan sonra en önemli kural basit: aynı ctx'yi veritabanı çağrısına kadar aynen iletin. Böylece zaman aşımları sadece handler'ın beklemeyi bırakmasını sağlamakla kalmaz, işi gerçekten durdurur.\n\ndatabase/sql ile context-dostu metotları tercih edin:\n\ngo\nfunc (s *Server) getUser(w http.ResponseWriter, r *http.Request) {\n ctx := r.Context()\n\n row := s.db.QueryRowContext(ctx,\n \"SELECT id, email FROM users WHERE id = $1\",\n r.URL.Query().Get(\"id\"),\n )\n\n var id int64\n var email string\n if err := row.Scan(\u0026id, \u0026email); err != nil {\n // handle below\n }\n}\n\n\n### Handler bütçesine uyan bir DB zaman aşımı seçin\n\nEğer handler bütçeniz 2 saniye ise, veritabanına sadece bunun bir dilimini verin. JSON kodlama, diğer bağımlılıklar ve hata işleme için zaman bırakın. Basit bir başlangıç noktası, Postgres'e toplam bütçenin %30–60'ını vermektir. 2s handler için bu 800ms–1.2s arası olabilir.\n\n### Bir sorguyu iptal ettiğinizde ne olur\n\nContext iptal edildiğinde, sürücü Postgres'e sorguyu durdurmasını söyler. Genelde bağlantı havuza geri döner ve yeniden kullanılabilir. İptal ağ problemleri sırasında olursa sürücü o bağlantıyı atabilir ve daha sonra yeni bir tane açabilir. Her halükarda, sonsuza dek bekleyen bir goroutine'den kaçınırsınız.\n\nHataları kontrol ederken zaman aşımlarını gerçek DB hatalarından farklı değerlendirin. Eğer errors.Is(err, context.DeadlineExceeded) ise süre doldu ve zaman aşımı dönmelisiniz. Eğer errors.Is(err, context.Canceled) ise istemci ayrıldı ve sessizce durmanız gerekir. Diğer hatalar normal sorgu problemleridir (kötü SQL, eksik satır, izinler).\n\n## Dış HTTP çağrılarına deadlinelerin iletilmesi\n\nHandler'ın bir deadline'ı varsa, dışa yapılan HTTP çağrıları da buna uyum sağlamalıdır. Aksi halde istemci vazgeçer ama sunucunuz yavaş upstream'i beklemeye devam eder ve goroutine, soket ve bellek işgal edilir.\n\nGiden istekleri ebeveyn context ile oluşturun ki iptal otomatik taşınsın:\n\ngo\nfunc fetchUser(ctx context.Context, url string) ([]byte, error) {\n\t// Add a small per-call cap, but never exceed the parent deadline.\n\tctx, cancel := context.WithTimeout(ctx, 800*time.Millisecond)\n\tdefer cancel()\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close() // always close, even on non-200\n\n\treturn io.ReadAll(resp.Body)\n}\n\n\nBu çağrı başına zaman aşımı bir güvenlik ağıdır. Ebeveyn request deadline hâlâ gerçek patrontur. Tüm istek için tek bir saat, riskli adımlar için küçük kaplar ekleyin.\n\nAyrıca transport seviyesinde zaman aşımları ayarlayın. Context isteği iptal eder, ama transport zaman aşımları yavaş el sıkışmalar ve başlık göndermeyen sunuculara karşı sizi korur.\n\nEkipleri ısıran bir detay: response body her yol için kapatılmalıdır. Erken döndüğünüzde (status kontrolü, JSON decode hatası, context timeout), yine de body'yi kapatın. Body sızıntıları bağlantı havuzunun tükenmesine ve "rastgele" gecikme patlamalarına yol açabilir.\n\nSomut bir senaryo: API'niz bir ödeme sağlayıcısını çağırıyor. İstemci 2s sonra vazgeçiyor ama upstream 30s takılıyor. İstek iptali ve transport zaman aşımları olmadan, her terkedilmiş istek için o 30 saniyeyi ödersiniz.\n\n## Tüm istek boyunca zaman aşımı bütçeleme\n\nTek bir istek genelde birden fazla yavaş şeyle temas eder: handler işi, bir veritabanı sorgusu ve bir veya daha fazla dış API. Her adımı cömertçe zaman sınırı ile verirseniz, toplam süre sessizce büyür ve kullanıcılar bunu hissetmeye başlar; sunucunuz birikmeye başlar.\n\nBütçeleme en basit düzeltmedir. Tüm istek için bir ebeveyn deadline belirleyin, sonra her bağımlılığa daha küçük bir dilim verin. Alt deadline'lar ebeveyninkinden daha erken olmalı ki hızlıca başarısız olun ve temiz bir hata dönmeye zaman kalsın.\n\nGerçek servislerde işe yarayan bazı pratik kurallar:\n\n- Önce toplam bütçeyi seçin (örneğin kullanıcıya yönelik endpoint için 2s).\n- Handler ek yükü ve yanıt formatlama için küçük bir tampon ayırın (örneğin 100–200ms).\n- Kalan süreyi bağımlılıklar arasında bölün.\n- Birden fazla dış çağrı varsa, her birini sınırlandırın; tek bir çağrı tüm bütçeyi yutmasın.\n- Eğer ebeveyn context'in sadece 120ms'si kaldıysa, normalde 300ms gerektiren bir bağımlılığı başlatmayın.\n\nBirbirleriyle çarpışan zaman aşımlarından kaçının. Eğer handler context'inizde 2s deadline var ama HTTP client'ınız 10s ise, güvendesiniz ama kafa karıştırıcıdır. Tersine olursa, client gereksiz nedenlerle erken kesebilir.\n\nArka plan işleri (denetim kayıtları, metrikler, e-postalar) için istek context'ini yeniden kullanmayın. İstemci iptallerinin önemli temizlik işlerini öldürmemesi için kendi kısa zaman aşımı olan ayrı bir context kullanın.\n\n## İsteklerin asılı kalmasına neden olan yaygın hatalar\n\nZaman aşımlarındaki hataların çoğu handler'da değildir. Genelde deadline'ın sessizce kaybolduğu bir ya da iki katman aşağıda olur. Kenarda zaman aşımları koysanız bile ortada bunları yok sayarsanız, goroutine'ler, DB sorguları veya HTTP çağrıları istemci gittikten sonra çalışmaya devam edebilir.\n\nEn sık görülen desenler basittir:\n\n- İstek context'ini bırakıp alt katmanları context.Background() (veya TODO) ile çağırmak. Bu, çalışmayı istemci iptali ve handler deadline'ından koparır.\n- ctx.Done() kontrol etmeden uyumak, yeniden denemek veya döngü kurmak. İstek iptal edildiğinde kodunuz beklemeye devam eder.\n- Her yardımcıyı kendi context.WithTimeout ile sarmak. Birçok zamanlayıcı ve kafa karıştırıcı deadline'lar ile sonuçlanır.\n- Engelleyici çağrılara (DB sorguları, giden HTTP, mesaj yayınları) ctx eklemeyi unutmak. Handler zaman aşımı, bağımlılık çağrısı bunu göz ardı ederse hiçbir işe yaramaz.\n- Zaman aşımlarını genel hatalar gibi ele alıp 500 dönmek. İstemciler sürenin tükendiğini net olarak görmelidir.\n\nKlasik bir başarısızlık: handler'da 2s zaman aşımı eklersiniz, sonra repository veritabanı sorgusu için context.Background() kullanır. Yük altındayken yavaş sorgu istemci vazgeçtikten sonra bile çalışmaya devam eder ve birikme başlar.\n\nTemeli düzeltin: çağrı yığını boyunca ctx'yi ilk argüman olarak iletin. Uzun iş içinde hızlı kontroller ekleyin, örneğin select { case <-ctx.Done(): return ctx.Err() default: }. context.DeadlineExceeded'i timeout yanıtına (çoğunlukla 504) ve context.Canceled'ı istemci-iptal tarzı yanıta (çoğunlukla 408 veya konvansiyonunuza göre 499) eşleyin.\n\n## Zaman aşımlarını uygulamada test etmek ve gözlemlemek\n\nZaman aşımları ancak gerçekleştiğini görüp sistemin temiz şekilde iyileştiğini doğrulayabiliyorsanız yardımcı olur. Bir şey yavaşladığında, istek durmalı, kaynaklar serbest kalmalı ve API yanıt verebilir durumda kalmalıdır.\n\n### Önemli olanı loglayın (ve tutarlı tutun)\n\nHer istek için aynı küçük alan setini loglayın ki normal isteklerle zaman aşımlarını karşılaştırabilesiniz. Context deadline'ını (varsa) ve işin neyle sona erdiğini dahil edin.\n\nYararlı alanlar: deadline (veya "none"), toplam geçen süre, iptal nedeni (timeout veya client canceled), kısa operasyon etiketi ("db.query users", "http.call billing") ve istek ID'si.\n\nMinimal bir desen şöyle gözükür:\n\ngo\nstart := time.Now()\ndeadline, hasDeadline := ctx.Deadline()\nerr := doWork(ctx)\nlog.Printf("op=%s hasDeadline=%t deadline=%s elapsed=%s err=%v",\n "getUser", hasDeadline, deadline.Format(time.RFC3339Nano), time.Since(start), err)\n\n\n### Kullanıcı şikayet etmeden önce zaman aşımlarını gösteren metrikler\n\nLoglar tek isteği debug etmeye yardımcı olur. Metrikler trendleri gösterir.\n\nBirkaç sinyal takip edin: rota ve bağımlılık bazında zaman aşımlarının sayısı, uçta eşzamanlı istekler (yük altında dengeye oturmalı), DB havuzu bekleme süresi ve gecikme yüzdelikleri (p95/p99) başarı vs timeout olarak ayrılmış hâlde. Bunlar genelde zaman aşımları yanlışken erken yükselir.\n\n### Zaman aşımlarını yerelde yeniden üretin (düzeltmeye güvenebilmek için)\n\nYavaşlığı öngörülebilir yapın. Bir handler'a debug-only gecikme ekleyin, bir DB sorgusunu kasıtlı olarak yavaşlatın veya uyuyan bir test sunucusu ile dış çağrıyı sarın. Sonra iki şeyi doğrulayın: timeout hatasını görüyorsunuz ve iptal olduktan sonra iş gerçekten duruyor.\n\nKüçük bir yük testi de yardımcı olur. 20–50 eşzamanlı isteği 30–60 saniye çalıştırıp bir zorunlu yavaş bağımlılık koyun. Goroutine sayısı ve uçta eşzamanlı istekler yükselip sonra dengeye oturmalı. Eğer tırmanmaya devam ederse bir şey context iptalini görmezden geliyor demektir.\n\n## Yayına almadan önce hızlı kontrol listesi\n\nZaman aşımları, bir isteğin bekleyebileceği her yerde uygulanırsa yardımcı olur. Deploy etmeden önce kod tabanınızı bir kez kontrol edin ve aynı kuralların her handler'da uygulandığını doğrulayın.\n\n- Her gelen istek sınırında açık bir zaman bütçesi var (router, middleware, handler). Sonsuz handler yok.\n- Her veritabanı sorgusuna istek context'i (veya bir child context) veriliyor ve context.DeadlineExceeded ile context.Canceled için hatalar kontrol ediliyor.\n- Her giden HTTP çağrısı http.NewRequestWithContext (veya req = req.WithContext(ctx)) kullanıyor ve client/transport seviyesinde zaman aşımları var (dial, TLS, response header). Üretim yollarında http.DefaultClient'a güvenmekten kaçının.\n- Hatalar tutarlı şekilde eşleniyor: zaman aşımları her yerde aynı API yanıtına (çoğunlukla 504) dönüşüyor, istemci iptalleri temiz şekilde eşleniyor (çoğunlukla 499 veya 408), ve iç zaman aşımları ham sürücü hatalarını sızdırmıyor.\n- Loglar ve metrikler zaman aşımlarını bariz kılıyor: handler adı, geçen süre ve hangi bağımlılığın zaman aşımına uğradığı.\n\nYayına almadan önce kısa bir "yavaş bağımlılık" tatbikatı yapmak değerlidir. Bir SQL sorgusuna yapay 2s gecikme ekleyin ve üç şeyi doğrulayın: handler zamanında dönüyor, DB çağrısı gerçekten duruyor (sadece handler beklemeyi bırakmıyor) ve loglar DB zaman aşımı olduğunu net söylüyor.\n\n## Gerçekçi bir örnek: bir istek, üç yavaş bağımlılık\n\nGET /v1/account/summary gibi bir endpoint hayal edin. Tek bir kullanıcı eylemi üç şeyi tetikliyor: PostgreSQL sorgusu (hesap + son aktiviteler) ve iki dış HTTP çağrısı (örneğin fatura durumu kontrolü ve profil zenginleştirme).\n\nTüm istek için sert 2s bütçe verin. Bütçe yoksa bir yavaş bağımlılık goroutine'leri, DB bağlantılarını ve belleği kilitleyebilir ve API her yerde zaman aşımına girmeye başlar.\n\nBasit bir bölüşüm: DB sorgusu için 800ms, dış çağrı A için 600ms ve dış çağrı B için 600ms.\n\nEbeveyn deadline'ını bildikten sonra onu iletin. Her bağımlılığa kendi küçük zaman aşımı verin ama yine de ebeveynin iptalinden etkilenir olsunlar.\n\ngo\nfunc AccountSummary(w http.ResponseWriter, r *http.Request) {\n ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)\n defer cancel()\n\n dbCtx, dbCancel := context.WithTimeout(ctx, 800*time.Millisecond)\n defer dbCancel()\n\n aCtx, aCancel := context.WithTimeout(ctx, 600*time.Millisecond)\n defer aCancel()\n\n bCtx, bCancel := context.WithTimeout(ctx, 600*time.Millisecond)\n defer bCancel()\n\n // Use dbCtx for QueryContext, aCtx/bCtx for outbound HTTP requests.\n}\n\n\nEğer dış çağrı B yavaşlar ve 2.5s sürerse, handler 600ms'de beklemeyi bırakmalı, uç işi iptal etmeli ve istemciye net bir zaman aşımı yanıtı döndürmelidir. İstemci asılı bir spinner yerine hızlı bir hata görür.\n\nLoglarınız hangi şeyin bütçeyi kullandığını açıkça göstermeli: örneğin DB çabuk bitti, dış A başarılı oldu, dış B kendi sınırına takıldı ve context deadline exceeded döndü.\n\n## Sonraki adımlar: API'nızda zaman aşımlarını standartlaştırın\n\nBir endpoint'te zaman aşımları ve iptal düzgün çalıştıktan sonra bunu tekrarlanabilir bir desene dönüştürün. Uçtan uca uygulayın: handler deadline, DB çağrıları ve giden HTTP. Sonra aynı yapıyı diğer endpoint'lere kopyalayın.\n\nSıkıcı parçaları merkezileştirmek işleri hızlandırır: bir boundary timeout helper, DB ve HTTP çağrılarında ctx'nin geçirilmesini garantileyen sarmalayıcılar ve tek bir hatalı eşleme ile log formatı.\n\nBu deseni hızlıca prototiplemek isterseniz, Koder.ai (koder.ai) chat prompt'tan Go handler'ları ve servis çağrılarını üretebilir; kaynağı dışa aktararak kendi timeout helper'larınızı ve bütçelerinizi uygulayabilirsiniz. Amaç tutarlılık: yavaş çağrılar erken durur, hatalar aynı görünür ve debug etmek kimin yazdığına bağlı olmaz.Yavaş bir istek beklerken sınırlı kaynakları tutar: bir goroutine, tamponlar ve yanıt nesneleri için bellek ve genellikle bir veritabanı bağlantısı ya da HTTP istemci bağlantısı. Aynı anda yeterince çok istek beklemeye başlarsa kuyruklar oluşur, gecikme tüm trafiğe yayılır ve her istek sonunda tamamlansa bile servis başarısız hale gelebilir.
Sınırı trafiğin giriş noktasında (proxy/gateway ve Go sunucusunda) belirleyin, handler içinde zamanlı bir context türetin ve bu ctx'yi veritabanı ve dış HTTP gibi her engelleyici çağrıya iletin. Süre dolduğunda hızlıca dönün, tutarlı bir zaman aşımı yanıtı verin ve iptal edilebilen tüm uç işleri durdurun.
context.WithTimeout(parent, d) belirli bir süre sonra durmak istiyorsanız kullanın — handler'larda en yaygın olanı budur. Zaten belirli bir kesme zamanı biliyorsanız context.WithDeadline(parent, t) kullanın. İçeride bir koşul işi erken durdurmalıysa (zaten cevap var veya istemci ayrıldı gibi) context.WithCancel(parent) kullanın.
Türetilmiş context'i oluşturduktan hemen sonra genellikle defer cancel() ile cancel fonksiyonunu çağırın. Cancel etmek zamanlayıcıyı serbest bırakır ve erken dönen kod yollarında alt iş parçacıklarına net bir durma sinyali gönderir.
Handler içinde tek bir request context oluşturun ve bloklayabilecek fonksiyonlara ilk argüman olarak iletin. Kod tabanında context.Background() veya context.TODO() araması yapın; bunlar sıklıkla iptal yayılımını kırar çünkü çalışmayı isteğin deadline'ından ayırır.
QueryContext, QueryRowContext ve ExecContext gibi context-dostu veritabanı metotlarını kullanın (veya sürücünüzün eşdeğerlerini). Context sona erdiğinde sürücü Postgres'e sorguyu iptal etmesini isteyebilir; böylece istek zaten bitmişken zamanı ve bağlantıları tüketmezsiniz.
Giden isteğe üstteki request context'ini bağlayın: http.NewRequestWithContext(ctx, ...). Ayrıca transport seviyesinde zaman aşımları yapılandırın; bu, bağlanma, TLS ve yanıt başlıklarını beklerken sizi korur. Hata veya 200 dışı yanıt yollarında bile response body'yi her zaman kapatın ki bağlantılar havuza geri dönsün.
Önce toplam bir bütçe belirleyin (örneğin kullanıcıya yönelik endpoint için 2s). Ardından her bağımlılığa daha küçük dilimler verin ve handler üstünde küçük bir tampon bırakın (örneğin 100–200ms). Birden fazla dış çağrı varsa her birini ayrı şekilde sınırlandırın, tek bir çağrının tüm bütçeyi yemesine izin vermeyin.
context.DeadlineExceeded genellikle 504 Gateway Timeout ile eşlenir; kısa bir mesaj olarak "request timed out" gibi dönebilirsiniz. context.Canceled genellikle istemcinin ayrıldığını gösterir; çoğu durumda daha fazla iş yapmamak ve gövde yazmadan durmak en iyisidir.
En sık yapılan hatalar: request context'ini kaybetmek (context.Background() kullanmak), ctx.Done() kontrol etmeden uyumak/yeniden denemek/döngü kurmak, bloklayıcı çağrılara ctx eklemeyi unutmak ve her yerde birbirleriyle çarpışan zaman aşımları yığmak. Bunlar handler'ların zaman aşımlarını görmezden gelmesine neden olur.