Корректное завершение задач
Корректно останавливайте задачи
«Корректное завершение задач» — бесплатный урок Go Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Go Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Go Academy содержит 4 уроков всего.
Корректная остановка заданий
Планировщик, принудительно остановленный во время выполнения задания, может повредить данные или оставить работу незавершённой. Корректное завершение означает: перестать принимать новые запуски, дать выполняющимся заданиям завершиться (до установленного крайнего срока), а затем выйти.
Ожидание сигналов
Перехватывайте сигналы OS, такие как SIGINT (Ctrl+C) и SIGTERM (остановка оркестратором), чтобы намеренно завершать работу.
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
fmt.Println("shutting down")signal.NotifyContext
Начиная с Go 1.16, доступен удобный вспомогательный механизм, который отменяет контекст при поступлении сигнала.
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
<-ctx.Done()Остановка планировщика
В robfig/cron вызов c.Stop() возвращает контекст, который завершается после окончания всех выполняющихся заданий. Дождитесь его, чтобы дать заданиям завершиться.
ctx := c.Stop() // stops scheduling, returns ctx
<-ctx.Done() // wait for running jobs
fmt.Println("all jobs finished")Передача отмены заданиям
Передавайте контекст каждому заданию, чтобы длительная работа могла быстро прерваться после начала завершения.
func job(ctx context.Context) {
select {
case <-time.After(time.Hour):
case <-ctx.Done():
return // bail out early
}
}Ограничение времени ожидания
Не ждите зависших заданий бесконечно. Используйте контекст с ограничением времени, чтобы завершение произошло даже в случае зависания задания.
shutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()WaitGroups для собственных планировщиков
Если Вы создаёте планировщик самостоятельно с помощью горутин, отслеживайте их через sync.WaitGroup и вызывайте Wait() во время завершения.
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); doWork() }()
// shutdown:
wg.Wait()Не начинайте новую работу
После начала завершения тикер или планировщик должны перестать срабатывать. Закрытие канала завершения или отмена контекста позволяет циклу увидеть сигнал и прекратить планирование новых запусков.
Идемпотентность помогает
Проектируйте задания так, чтобы их было безопасно запускать повторно. Если задание было прервано в середине выполнения и повторно запущено после перезапуска, идемпотентная логика предотвращает повторные эффекты, например повторную отправку писем или двойное списание средств.
Полный шаблон
Объединим всё вместе: контекст, который уведомляется о сигнале, вызов Stop у cron, возвращающий контекст ожидания завершения, и ограничение времени ожидания. Это стандартный каркас корректного завершения сервисов с запланированными заданиями.
Готовый к запуску пример: корректная остановка с контекстом
Эта автономная программа запускает периодический обработчик и корректно останавливает его через отмену контекста, дожидаясь завершения текущего сигнала тикера.
package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
t := time.NewTicker(5 * time.Millisecond)
defer t.Stop()
for {
select {
case <-t.C:
fmt.Println("working")
case <-ctx.Done():
fmt.Println("stopping cleanly")
return
}
}
}()
time.Sleep(17 * time.Millisecond)
cancel() // signal shutdown
wg.Wait() // wait for worker to finish
fmt.Println("shutdown complete")
}Проверка знаний
Проверьте, насколько хорошо Вы поняли корректное завершение заданий.
Итоги
Вы изучили корректное завершение заданий:
- Перехватывайте SIGINT/SIGTERM, желательно через
signal.NotifyContext cron.Stop()возвращает контекст, который дожидается завершения выполняющихся заданий- Передавайте контекст заданиям и ограничивайте время ожидания с помощью таймера
- Делайте задания идемпотентными, чтобы их повторные запуски были безопасными
Изучай Go с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 51
- Уроки
- 203
Часто задаваемые вопросы
Урок «Корректное завершение задач» бесплатный?
Да — полный текст урока «Корректное завершение задач» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Go Academy, подпишись на CoddyKit PRO. Курс Go Academy содержит 4 уроков всего.
Чему я научусь в уроке «Корректное завершение задач»?
Корректно останавливайте задачи Ты практикуешь Go Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Go Academy?
Предыдущий опыт не требуется. Go Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Корректное завершение задач»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Go Academy?
Да. Каждый урок Go Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Планирование по времени
- Библиотека robfig/cron
- Тикеры для интервалов
- Корректное завершение задач