2026'da Go Context Paketi: İptal, Timeout ve Mülakat Soruları
Go context paketi hakkında kapsamlı rehber - Context arayüzünden WithCancel ve WithTimeout'a, ileri düzey kalıplara ve mülakat sorularına kadar her şey.

Go context paketi, API sınırları arasında süre sınırları, iptal sinyalleri ve istek kapsamlı değerleri taşımak için standart mekanizmayı sağlar. Her üretim Go uygulaması context kullanır: HTTP handler'ları, veritabanı sorguları, gRPC çağrıları ve arka plan worker'ları düzgün kapatma ve timeout yönetimi için buna bağımlıdır.
Context, Go mülakatlarında en sık sorulan konulardan biridir. Mülakatçılar adayların context yayılımını açıklamasını, doğru iptal işleme göstermesini ve context'i struct'larda saklama gibi yaygın hatalardan kaçınmasını bekler.
Context Arayüzü ve Dört Metodu
Context arayüzü, her context implementasyonunun karşılaması gereken dört metod tanımlar. Bu metodları anlamak, etkili context kullanımının temelini oluşturur.
type Context interface {
// Deadline returns the time when work should be canceled
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that closes when the context is canceled
Done() <-chan struct{}
// Err returns the reason why Done was closed
Err() error
// Value returns the value associated with key, or nil
Value(key any) any
}Done() sadece okuma amaçlı bir kanal döndürür. Bu kanal kapandığında, onu dinleyen herhangi bir goroutine sinyali anında alır. <-ctx.Done() kalıbı iptal gerçekleşene kadar bloke eder. Err() nedenini açıklar: açıkça iptal edildiğinde context.Canceled, timeout veya son tarih geçtiğinde context.DeadlineExceeded.
Background ve TODO ile Context Oluşturma
İki fonksiyon kök context'ler oluşturur: context.Background() ve context.TODO(). Her ikisi de hiçbir zaman iptal edilmeyen boş olmayan context'ler döndürür.
package main
import (
"context"
"log"
"net/http"
)
func main() {
// Background: the root context for your application
ctx := context.Background()
// Use it as parent for derived contexts
server := &http.Server{Addr: ":8080"}
// TODO: placeholder when context source is unclear
// Static analysis tools can flag context.TODO() for review
processLegacyData(context.TODO())
}
func processLegacyData(ctx context.Context) {
// Context parameter enables future cancellation support
log.Println("Processing data...")
}Background() gelen istekler, main fonksiyonları ve başlatma kodu için üst eleman olarak hizmet eder. TODO() doğru context kaynağı henüz belirlenmediğinde refactoring sırasında placeholder görevi görür. Statik analiz araçları TODO() kullanımını inceleme için işaretleyebilir.
WithCancel ve WithCancelCause ile İptal
Manuel iptal, üst goroutine'lerin alt goroutine'lere işin durdurulması gerektiğini sinyal etmesine olanak tanır. Bu kalıp worker havuzlarında, arka plan görevlerinde ve graceful shutdown implementasyonlarında görülür.
package main
import (
"context"
"errors"
"fmt"
"time"
)
func worker(ctx context.Context, id int, results chan<- int) {
for {
select {
case <-ctx.Done():
// Check why cancellation occurred
if cause := context.Cause(ctx); cause != nil {
fmt.Printf("Worker %d stopped: %v\n", id, cause)
}
return
default:
// Simulate work
time.Sleep(100 * time.Millisecond)
results <- id * 10
}
}
}
func main() {
// WithCancelCause provides error context
ctx, cancel := context.WithCancelCause(context.Background())
results := make(chan int, 10)
// Start 3 workers
for i := 1; i <= 3; i++ {
go worker(ctx, i, results)
}
// Collect some results
for i := 0; i < 5; i++ {
fmt.Println("Result:", <-results)
}
// Cancel with a specific reason
cancel(errors.New("shutdown requested by user"))
// context.Cause retrieves the cancellation reason
time.Sleep(50 * time.Millisecond)
fmt.Println("Cause:", context.Cause(ctx))
}Go 1.20'de tanıtılan WithCancelCause, düz WithCancel'dan daha zengin hata bilgisi sağlar. context.Cause() fonksiyonu cancel fonksiyonuna geçirilen hatayı alır ve karmaşık sistemlerde hata ayıklamayı kolaylaştırır.
Go mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
İstek İşleme için Timeout ve Son Tarihler
HTTP handler'ları, veritabanı çağrıları ve harici API istekleri her zaman timeout'lara sahip olmalıdır. Context paketi bu amaçla WithTimeout ve WithDeadline sunar. Her ikisi de süre dolduğunda otomatik olarak iptal olan context'ler oluşturur.
package main
import (
"context"
"fmt"
"time"
)
// fetchFromAPI simulates an HTTP call
func fetchFromAPI(ctx context.Context, endpoint string) (string, error) {
// Simulate variable response time
responseTime := time.Duration(100+endpoint[0]%150) * time.Millisecond
select {
case <-time.After(responseTime):
return fmt.Sprintf("Response from %s", endpoint), nil
case <-ctx.Done():
return "", ctx.Err()
}
}
func main() {
// WithTimeout: relative duration
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel() // Always call cancel to release resources
result, err := fetchFromAPI(ctx, "api.example.com/users")
if err != nil {
if err == context.DeadlineExceeded {
fmt.Println("Request timed out")
} else {
fmt.Println("Request canceled")
}
return
}
fmt.Println(result)
// WithDeadline: absolute time
deadline := time.Now().Add(500 * time.Millisecond)
ctx2, cancel2 := context.WithDeadline(context.Background(), deadline)
defer cancel2()
result2, _ := fetchFromAPI(ctx2, "api.example.com/orders")
fmt.Println(result2)
}defer cancel() kalıbı, operasyon timeout'tan önce tamamlansa bile kaynakların serbest bırakılmasını sağlar. Bu çağrının atlanması kaynak sızıntısına neden olur: context'in timer goroutine'i timeout süresi dolana kadar aktif kalır.
WithValue ile İstek Kapsamlı Değerler
WithValue istek kapsamlı verileri context'e ekler. Yaygın kullanım durumları arasında istek ID'leri, kimlik doğrulama token'ları ve izleme span'ları bulunur. Resmi dokümantasyon çakışmaları önlemek için özel türlerin anahtar olarak kullanılmasını vurgular.
package main
import (
"context"
"fmt"
"log"
"net/http"
)
// Define custom key types to avoid collisions
type contextKey string
const (
requestIDKey contextKey = "requestID"
userIDKey contextKey = "userID"
)
// middleware adds request ID to context
func requestIDMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestID := r.Header.Get("X-Request-ID")
if requestID == "" {
requestID = generateRequestID()
}
// Create new context with request ID
ctx := context.WithValue(r.Context(), requestIDKey, requestID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
// handler retrieves values from context
func handler(w http.ResponseWriter, r *http.Request) {
requestID, ok := r.Context().Value(requestIDKey).(string)
if !ok {
requestID = "unknown"
}
log.Printf("[%s] Processing request", requestID)
fmt.Fprintf(w, "Request ID: %s", requestID)
}
func generateRequestID() string {
return fmt.Sprintf("req-%d", time.Now().UnixNano())
}
import "time"
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
http.ListenAndServe(":8080", requestIDMiddleware(mux))
}Context değerleri değişmez bir zincir oluşturur: her WithValue çağrısı üst elemanı saran yeni bir context oluşturur. Aramalar bu zinciri dolaşır, bu da derin iç içe değerlere erişimi yavaşlatır. Yalnızca istek kapsamlı verileri depolanmalı, uygulama yapılandırması veya opsiyonel parametreler değil.
WithoutCancel ve AfterFunc Yardımcı Araçları
Go 1.21, temizlik görevleri gibi üst iptalden bağımsız olarak tamamlanması gereken operasyonlar için WithoutCancel ekledi. AfterFunc context iptali gerçekleştiğinde çalışacak bir callback planlar.
package main
import (
"context"
"fmt"
"log"
"time"
)
func saveAuditLog(ctx context.Context, message string) error {
// Use WithoutCancel: audit logs must complete even if request canceled
cleanCtx := context.WithoutCancel(ctx)
// Simulate database write
select {
case <-time.After(50 * time.Millisecond):
log.Printf("Audit: %s", message)
return nil
case <-cleanCtx.Done():
// This branch never executes: WithoutCancel context is never canceled
return cleanCtx.Err()
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
// AfterFunc: register cleanup when context ends
stop := context.AfterFunc(ctx, func() {
fmt.Println("Context ended, running cleanup")
})
// Perform operation
time.Sleep(50 * time.Millisecond)
// Cancel stops the AfterFunc from running if called before context ends
if stop() {
fmt.Println("Cleanup prevented")
}
cancel()
// Audit log completes despite parent cancellation
saveAuditLog(ctx, "Operation completed")
}WithoutCancel üst context'ten değerleri korur ancak iptal sinyalini yok sayar. Bu kalıp loglama, metrik yayınlama ve istek sonucundan bağımsız olarak başarılı olması gereken veritabanı commit'leri için uygundur.
Mülakat Soruları ve Cevapları
Go teknik mülakatına hazırlanmak, context iç yapısını ve en iyi uygulamaları anlamayı gerektirir. Bu sorular backend servisleri için Go kullanan şirketlerde sıkça karşılaşılır. Daha fazla Go mülakat hazırlığı için Context Paketi mülakat soruları modülüne bakılabilir.
Context neden ilk parametre olmalı?
Go ekibi context yayılımını görünür ve tutarlı kılmak için bu konvansiyonu oluşturdu. Context'i ilk sıraya koymak okuyuculara fonksiyonun iptali dikkate aldığını sinyal eder. Standart kütüphane bu kalıbı takip eder: http.Request.Context(), database/sql.QueryContext() ve grpc.UnaryInterceptor hepsi context'i ilk argüman olarak bekler.
Context'i struct'ta saklarsanız ne olur?
Context'i saklamak istek yaşam döngüsü modelini bozar. Bir struct için oluşturulduğu istekten daha uzun yaşayabilir ve operasyonların eski iptal sinyalleri kullanmasına veya yeni son tarihleri kaçırmasına neden olabilir. Context dokümantasyonu bu kalıba karşı açıkça uyarır.
// BAD: context stored in struct
type Service struct {
ctx context.Context // Never do this
}
// GOOD: pass context to each method
type Service struct{}
func (s *Service) Process(ctx context.Context, data []byte) error {
// Context flows through the call chain
return s.save(ctx, data)
}Goroutine'lerde context nasıl işlenir?
Goroutine'ler ana döngülerinde veya select ifadelerinde ctx.Done() kontrol etmelidir. Done kanalını yok saymak goroutine sızıntısı oluşturur: üst fonksiyon döner ancak goroutine kaynakları tüketmeye devam eder.
// Correct pattern for long-running goroutines
func processStream(ctx context.Context, stream <-chan Data) {
for {
select {
case <-ctx.Done():
log.Println("Shutting down processor")
return
case data, ok := <-stream:
if !ok {
return
}
handle(data)
}
}
}context.TODO() ne zaman kullanılmalı?
Eski koda context desteği eklerken artımlı refactoring sırasında TODO() kullanılmalıdır. Uygun context yayılımı gereken yerleri işaretler. Üretim kodu sonunda tüm TODO() çağrılarını istek handler'larından veya uygulama başlatmasından gelen gerçek context'lerle değiştirmelidir. Go eşzamanlılık kalıpları hakkında daha fazla bilgi için Go Concurrency: Goroutines and Channels makalesine bakılabilir.
Kaçınılması Gereken Yaygın Hatalar
Context'in yanlış kullanımı yük altında veya kapatma sekansları sırasında ortaya çıkan ince hatalara yol açar. Bu kalıpları tanımak üretim olaylarını önler.
package main
import (
"context"
"time"
)
// MISTAKE 1: Ignoring context cancellation
func badWorker(ctx context.Context) {
for {
// Missing select on ctx.Done()
doExpensiveWork() // Never stops when context canceled
}
}
// MISTAKE 2: Not calling cancel
func leakyTimeout() {
ctx, _ := context.WithTimeout(context.Background(), time.Second)
// Timer goroutine leaks until timeout expires
_ = ctx
}
// MISTAKE 3: Using string keys for values
func collisionProne(ctx context.Context) context.Context {
// Different packages might use same string key
return context.WithValue(ctx, "userID", 123) // Bad
}
// CORRECT versions
func goodWorker(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
doExpensiveWork()
}
}
}
func properTimeout() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel() // Always release resources
_ = ctx
}
type userIDKey struct{}
func collisionSafe(ctx context.Context) context.Context {
return context.WithValue(ctx, userIDKey{}, 123) // Good
}
func doExpensiveWork() {}Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Üretimde Go Context Kullanımı için Temel Çıkarımlar
- Context fonksiyonlara ilk parametre olarak geçirilmeli, asla struct'larda saklanmamalıdır
- Kaynak sızıntısını önlemek için
WithTimeout,WithDeadlineveyaWithCancelsonrası her zamandefer cancel()çağrılmalıdır - Karmaşık iptal zincirlerinde daha iyi hata ayıklama için
WithCancelCausevecontext.Cause()kullanılmalıdır - Graceful shutdown sağlamak ve sızıntıları önlemek için goroutine döngülerinde
<-ctx.Done()kontrol edilmelidir - Paketler arasında çakışmaları önlemek için
WithValueiçin özel anahtar türleri kullanılmalıdır - Üst iptalden bağımsız olarak tamamlanması gereken temizlik operasyonları için
WithoutCanceluygulanmalıdır - Uygulama başlatması için
context.Background()tercih edilmeli,context.TODO()yalnızca refactoring sırasında kullanılmalıdır
Go kodundaki hatayı bulabilir misin?
Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Yazan:
Anthony Fillion-MailletSharpSkill kurucusu
10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.
29 Ağustos 2026 tarihinde güncellendi
Etiketler
Paylaş
İlgili makaleler

2026'da Go Hata Yönetimi: Kalıplar, Sarmalama ve Teknik Mülakat Soruları
Go hata yönetimi kalıplarının kapsamlı rehberi: error arayüzü, sentinel hatalar, %w ile sarmalama, errors.Is, errors.As ve teknik mülakatlarda karşılaşılan sorular.

Go Tasarim Desenleri: Go Gelistiricileri icin Temel Desenler ve Mulakat Sorulari
Go tasarim desenlerinin kapsamli rehberi: Functional Options, Strategy, Factory, Observer ve Middleware desenleri. Pratik kod ornekleri ve Go mulakat sorulari.

En çok sorulan 25 Go mülakat sorusu: tam geliştirici rehberi
Go mülakatlarına hâkim olmak için en çok sorulan 25 soru. Goroutine, channel, arayüz ve eşzamanlılık desenleri kod örnekleriyle.