GoDasturchi
Graceful Shutdown

Graceful Shutdown

Yumshoq to'xtatish (Graceful Shutdown)

"Graceful Shutdown" darsini (Cloud Patterns kursida) eslang: serverni to'satdan o'chirish o'rniga, unga "tugatishga tayyorlaning" deb ELCHI yuborib, joriy ishlarni YAKUNLASHGA vaqt berish kerak. Task Queue uchun bu AYNIQSA muhim: agar server worker'lar hali vazifa bajarayotganda TO'SATDAN o'chirilsa, o'sha vazifalar YO'QOLADI — hech qachon tugallanmaydi.

example.go
package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type Task struct {
	ID string
}

// worker — context bekor qilinganda ISHNI TO'XTATADI, lekin
// joriy vazifani hali ham TUGATADI
func worker(ctx context.Context, tasks <-chan *Task, wg *sync.WaitGroup, processed *[]string, mu *sync.Mutex) {
	defer wg.Done()
	for {
		select {
		case task, ok := <-tasks:
			if !ok {
				return
			}
			mu.Lock()
			*processed = append(*processed, task.ID)
			mu.Unlock()
		case <-ctx.Done():
			return
		}
	}
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
	defer cancel()

	tasks := make(chan *Task, 3)
	tasks <- &Task{ID: "task-1"}
	tasks <- &Task{ID: "task-2"}
	close(tasks)

	var wg sync.WaitGroup
	var mu sync.Mutex
	var processed []string

	wg.Add(1)
	go worker(ctx, tasks, &wg, &processed, &mu)
	wg.Wait()

	fmt.Println(len(processed))
}

select bilan IKKI YO'NALISHNI kuzatish — "Select Statement" darsida ko'rgan naqsh: worker HAR bir aylanishda YOKI navbatdan yangi vazifa keladimi (case task, ok := <-tasks), YOKI vaqt tugab, ctx bekor qilinganidan (case <-ctx.Done()) qaysi biri OLDIN sodir bo'lishini kuzatadi. Bu — worker'ga "vaqt tugasa ham, hozirgi ishni tashlab qochma, lekin YANGI ish qabul qilma" degan xulq-atvorni beradi.

Production'da bu g'oya odatda ikki bosqichli bo'ladi: birinchi signal kelganda "yangi vazifa qabul qilishni TO'XTAT", lekin JORIY vazifalar tugashini KUT (masalan qo'shimcha sync.WaitGroup), va faqat SHUNDAN keyin dasturni butunlay yopish. Bu — "http.Server.Shutdown" darsida ko'rgan aynan shu tamoyilning Task Queue kontekstidagi ko'rinishi.

>_ Exercise

Kontekst allaqachon bekor qilingan holatda, worker hech qanday vazifani qayta ishlamasligini tekshiring.

  • context.WithCancel bilan ctx yarating va DARHOL cancel() ni chaqiring
  • tasks kanalini BO'SH holda (hech narsa yubormasdan) qoldiring
  • worker'ni ishga tushirib, wg.Wait() qiling, so'ng len(processed)ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

select va context.Done() birgalikda, worker'ga "vaqt tugasa ham joriy ishni yakunlash, lekin yangi ish qabul qilmaslik" imkonini beradi — bu Task Queue'ni to'satdan emas, balki yumshoq (graceful) to'xtatish uchun zarur.

NEXT UP

Project Recap & Next Steps

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Graceful Shutdown

Yumshoq to'xtatish (Graceful Shutdown)

"Graceful Shutdown" darsini (Cloud Patterns kursida) eslang: serverni to'satdan o'chirish o'rniga, unga "tugatishga tayyorlaning" deb ELCHI yuborib, joriy ishlarni YAKUNLASHGA vaqt berish kerak. Task Queue uchun bu AYNIQSA muhim: agar server worker'lar hali vazifa bajarayotganda TO'SATDAN o'chirilsa, o'sha vazifalar YO'QOLADI — hech qachon tugallanmaydi.

example.go
package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type Task struct {
	ID string
}

// worker — context bekor qilinganda ISHNI TO'XTATADI, lekin
// joriy vazifani hali ham TUGATADI
func worker(ctx context.Context, tasks <-chan *Task, wg *sync.WaitGroup, processed *[]string, mu *sync.Mutex) {
	defer wg.Done()
	for {
		select {
		case task, ok := <-tasks:
			if !ok {
				return
			}
			mu.Lock()
			*processed = append(*processed, task.ID)
			mu.Unlock()
		case <-ctx.Done():
			return
		}
	}
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
	defer cancel()

	tasks := make(chan *Task, 3)
	tasks <- &Task{ID: "task-1"}
	tasks <- &Task{ID: "task-2"}
	close(tasks)

	var wg sync.WaitGroup
	var mu sync.Mutex
	var processed []string

	wg.Add(1)
	go worker(ctx, tasks, &wg, &processed, &mu)
	wg.Wait()

	fmt.Println(len(processed))
}

select bilan IKKI YO'NALISHNI kuzatish — "Select Statement" darsida ko'rgan naqsh: worker HAR bir aylanishda YOKI navbatdan yangi vazifa keladimi (case task, ok := <-tasks), YOKI vaqt tugab, ctx bekor qilinganidan (case <-ctx.Done()) qaysi biri OLDIN sodir bo'lishini kuzatadi. Bu — worker'ga "vaqt tugasa ham, hozirgi ishni tashlab qochma, lekin YANGI ish qabul qilma" degan xulq-atvorni beradi.

Production'da bu g'oya odatda ikki bosqichli bo'ladi: birinchi signal kelganda "yangi vazifa qabul qilishni TO'XTAT", lekin JORIY vazifalar tugashini KUT (masalan qo'shimcha sync.WaitGroup), va faqat SHUNDAN keyin dasturni butunlay yopish. Bu — "http.Server.Shutdown" darsida ko'rgan aynan shu tamoyilning Task Queue kontekstidagi ko'rinishi.

>_ Exercise

Kontekst allaqachon bekor qilingan holatda, worker hech qanday vazifani qayta ishlamasligini tekshiring.

  • context.WithCancel bilan ctx yarating va DARHOL cancel() ni chaqiring
  • tasks kanalini BO'SH holda (hech narsa yubormasdan) qoldiring
  • worker'ni ishga tushirib, wg.Wait() qiling, so'ng len(processed)ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

select va context.Done() birgalikda, worker'ga "vaqt tugasa ham joriy ishni yakunlash, lekin yangi ish qabul qilmaslik" imkonini beradi — bu Task Queue'ni to'satdan emas, balki yumshoq (graceful) to'xtatish uchun zarur.

NEXT UP

Project Recap & Next Steps