
در برنامهنویسی Go، زمانی که با عملیات همزمان (goroutine)، درخواستهای شبکهای، اتصال به دیتابیس یا سیستمهای توزیعشده سروکار داریم، باید بتوانیم اجرای یک عملیات را در موقعیتهای مختلف متوقف یا کنترل کنیم.
Context دقیقاً برای همین هدف ساخته شده است.
در این مقاله بهصورت کامل و عملی یاد میگیرید:
Context دقیقاً چیست و چرا وجود دارد؟
انواع Context: Background, TODO
Context با timeout، deadline، cancel
Context برای مدیریت goroutineها
ارسال اطلاعات در Context
یک مثال کاملاً عملی: API با تایماوت و لغو عملیات
Context یک مکانیزم استاندارد در Go است که برای موارد زیر استفاده میشود:
وقتی یک درخواست لغو میشود، تمام goroutineهای مرتبط با آن باید متوقف شوند.
برای جلوگیری از بلاک شدن سیستم.
اطلاعات سبک (مثل request id) را میتوان به صورت امن در Context جابهجا کرد.
وقتی والد لغو شود، همه کارهای فرزند نیز لغو میشوند.
در Go، Context یک interface با ۴ تابع اصلی است:
type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key any) any }
معنی هر کدام:

ریشهٔ درخت Context. معمولاً برای شروع اپلیکیشن.
وقتی هنوز نمیدانیم چه Context لازم داریم.
ctx, cancel := context.WithCancel(context.Background()) defer cancel()
لغو عملیات:
cancel()
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel()
بعد از 3 ثانیه، ctx.Done() بسته میشود.
deadline := time.Now().Add(2 * time.Second) ctx, cancel := context.WithDeadline(context.Background(), deadline) defer cancel()
طبق مستندات Go:
فقط اطلاعات سبک، غیر حساس و غیر ضروری باید در Context ذخیره شود.
برای دادههای سنگین یا state از آن استفاده نکنید.
مثال:
ctx := context.WithValue(context.Background(), "requestID", "ABC-123")
در این مثال یک API میسازیم که درخواستهای سنگین را با Context مدیریت میکند.
وقتی کار بیش از حد طول کشید → خودکار قطع شود
اگر کلاینت درخواست را لغو کرد → Goroutineها هم لغو شوند
همراه با log و requestID
package main import ( "context" "fmt" "log" "net/http" "time" ) func main() { http.HandleFunc("/process", handler) fmt.Println("Server running on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } func handler(w http.ResponseWriter, r *http.Request) { // ساخت context با timeout ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second) defer cancel() // اضافه کردن requestID به context ctx = context.WithValue(ctx, "requestID", time.Now().UnixNano()) resultChan := make(chan string) // شروع یک عملیات سنگین go func() { // شبیهسازی کار ۵ ثانیهای time.Sleep(5 * time.Second) resultChan <- "Operation Completed" }() select { case <-ctx.Done(): // Timeout یا لغو شدن log.Println("Canceled:", ctx.Value("requestID"), ctx.Err()) http.Error(w, "Request Timeout", http.StatusRequestTimeout) return case result := <-resultChan: // موفقیتآمیز fmt.Fprintln(w, result) } }
برای دسترسی به سورسکد کامل مثال Context در Golang، به ریپازیتوری اختصاصی این مقاله در GitHub مراجعه کنید:
https://github.com/h-agharezaei/go-context-02.git
زمان پیشفرض عملیات ۵ ثانیه است ولی Context فقط ۳ ثانیه فرصت میدهد.
بنابراین:
عملیات به اتمام نمیرسد
ctx.Done() بعد از ۳ ثانیه بسته میشود
درخواست لغو میشود
Goroutine پاکسازی میشود
ویژگی مهم
اگر کلاینت (مثلاً Postman) درخواست را Cancel کند، سرویس Go بهطور خودکار Context را Cancel میکند.
✔ همیشه Context را در اولین آرگومان تابع قرار دهید:
func fetchData(ctx context.Context) {}
✔در توابع سطح پایین (service، repo، helper)، نباید از Background ، TODO یا WithCancel برای ساختن context استفاده کنید. Context باید از caller بیاید.
✔ از Context برای انتقال اطلاعات مهم یا ساختارهای سنگین استفاده نکنید
✔ برای database، http، grpc حتماً از Context استفاده کنید
✔ Context باید توسط caller مدیریت شود، نه callee
Context یکی از مهمترین ابزارهای Go برای مدیریت:
زمان اجرای عملیات
لغو کارها
کنترل goroutineها
جلوگیری از memory leak
ارتباط بهتر بین لایههای نرمافزار
Context چیست و چرا استفاده میشود
انواع Context
Timeout، Deadline و Cancel
انتقال مقدار
یک مثال واقعی در سطح production