Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+1 487новых вакансий за сутки·92 551вакансия открыта сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании7 220
РезюмеAIПодготовкаСтатьи
BoostТарифыBoost
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 402 кандидата открыты к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python17 105
  • Облачные технологии14 073
  • QA вакансии3 460
  • Backend вакансии2 098
  • Инженер данных1 805
  • Продакт-менеджер1 266

Разработка

  • Android1 866
  • iOS1 699
  • Fullstack вакансии979
  • AI вакансии951
  • Frontend вакансии742
  • Mobile вакансии44

По стеку

  • Go8 651
  • Java6 544
  • Node.js2 018
  • .NET1 719
  • Kotlin1 623
  • Rust1 453
  • C#709
  • PHP683
  • C++571

DevOps и инфраструктура

  • Kubernetes7 763
  • DevOps вакансии6 057
  • Linux-инфраструктура5 492
  • Terraform / IaC4 261
  • CI/CD3 240
  • Мониторинг и Observability1 783
  • SRE566
  • Кибербезопасность453

Аналитика и данные

  • Data Scientist1 140
  • Бизнес-аналитик930
  • Аналитик данных853
  • Системный аналитик154

Другие направления

  • Проджект-менеджер615
  • UI/UX дизайн146
  • Ручное тестирование14

По регионам

  • Вакансии в США43 685
  • Вакансии в Европе23 862
  • Вакансии в Канаде4 413
  • Работа в России3 909

По формату

  • Удалённые вакансии73 887
  • Релокация в США43 685
  • Гибридная работа12 392
  • Офисная работа7 088

По уровню

  • Senior вакансии42 236
  • Middle вакансии20 545
  • Junior вакансии6 653

Сейчас нанимают

Все компании
  • Wise190 вакансий
  • Rakuten189 вакансий
  • ASML166 вакансий
  • Grab138 вакансий
  • Celonis39 вакансий
  • Spotify36 вакансий
  • Adyen29 вакансий
  • Infobip28 вакансий
  • Monzo20 вакансий
  • Darktrace16 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме GinВсе вопросы
GinSeniorТеория

Как goroutine взаимодействуют с Context Gin — почему не следует передавать *gin.Context в goroutine?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

*gin.Context небезопасен для goroutine: после завершения хендлера Gin возвращает его в sync.Pool. Передавайте в goroutine только скопированные значения или c.Copy(), а для отмены — context.Context из c.Request.Context().

Правильный паттерн: копировать нужные данные до запуска goroutine

func HandleOrder(c *gin.Context) {
	// Извлекаем всё нужное до запуска goroutine
	userID := c.GetString("user_id")
	var req OrderRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	// Копируем контекст запроса (стандартный context.Context, НЕ *gin.Context)
	ctx := c.Request.Context()

	go func(ctx context.Context, uid string, order OrderRequest) {
		if err := processOrder(ctx, uid, order); err != nil {
			log.Printf("order processing failed: %v", err)
		}
	}(ctx, userID, req)

	c.JSON(202, gin.H{"status": "accepted"})
}

Почему *gin.Context нельзя передавать в goroutine

*gin.Context — не потокобезопасная структура. Gin возвращает объект контекста в пул (sync.Pool) сразу после завершения цепочки обработчиков. Если goroutine получает указатель на контекст и обращается к нему после того, как основной хендлер вернул управление, она работает с уже «мусорным» или повторно используемым объектом. Это приводит к гонкам данных и непредсказуемому поведению.

Что происходит под капотом

Gin хранит пул контекстов в Engine.pool *sync.Pool. После возврата хендлера вызывается engine.pool.Put(c). При следующем запросе тот же объект достаётся из пула и переписывается. Goroutine, запущенная в хендлере, может читать уже чужие данные или писать в чужой ResponseWriter.

Использование c.Copy() для передачи копии контекста

Gin предоставляет метод c.Copy(), который создаёт снимок gin.Context с отвязанным writermem. Копия безопасна для чтения в goroutine, но запись в ResponseWriter через неё невозможна (что правильно).

func HandleNotification(c *gin.Context) {
	cCopy := c.Copy() // создаём безопасную копию

	go func() {
		// Читаем из копии: заголовки, params, keys
		token := cCopy.GetHeader("Authorization")
		platform := cCopy.Query("platform")
		sendPushNotification(token, platform)
	}()

	c.JSON(200, gin.H{"ok": true})
}

Работа с context.Context внутри goroutine

Для отмены и таймаутов передавайте context.Context из запроса, а не весь gin.Context:

func HandleExport(c *gin.Context) {
	// context.Context с дедлайном
	ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
	defer cancel()

	resultCh := make(chan []byte, 1)
	errCh := make(chan error, 1)

	go func() {
		data, err := generateReport(ctx)
		if err != nil {
			errCh <- err
			return
		}
		resultCh <- data
	}()

	select {
	case data := <-resultCh:
		c.Data(200, "application/pdf", data)
	case err := <-errCh:
		c.JSON(500, gin.H{"error": err.Error()})
	case <-ctx.Done():
		c.JSON(504, gin.H{"error": "timeout"})
	}
}

Подводные камни

  • c.Copy() не копирует тело запроса. Request.Body — это io.ReadCloser, читается один раз. Если хендлер уже прочитал тело (через ShouldBindJSON), goroutine получит пустой Body.
  • Запись в ResponseWriter из goroutine — data race. Даже через c.Copy() ResponseWriter заблокирован; попытка записать ответ в goroutine после завершения хендлера завершится паникой или гонкой.
  • context.Context из Request может быть отменён. Когда клиент закрыл соединение, c.Request.Context() отменяется. Если goroutine должна продолжить работу независимо, передавайте context.Background() или специальный сервисный контекст.
  • sync.Pool и GC. Объект из пула может быть собран GC, если пул не удерживает ссылку. Никогда не кешируйте *gin.Context в глобальных переменных.
  • Goroutine leak при долгих задачах. Запускайте фоновые задачи через управляемый worker pool, а не «голые» goroutine — иначе при всплеске нагрузки будет тысячи goroutine без ограничения.
  • Логирование через c после завершения хендлера. Вызов c.Get("logger") из goroutine может вернуть нулевое значение или значение другого запроса.

Типичные ошибки

  • Давать ответ про goroutine и *gin.Context только на уровне определения, не показывая поведение в реальном приложении.
  • Игнорировать границы ответственности вокруг темы «goroutine и *gin.Context»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
  • Не связывать goroutine и *gin.Context с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.

Что проверяет интервьюер

  • Точно объясняет, что именно делает goroutine и *gin.Context и где это используется в Go-коде.
  • Связывает goroutine и *gin.Context с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
  • Не изобретает API и опирается на реальные контракты официальной документации.

Как вы знаете этот вопрос?

Проверить себя по теме Gin →

Источники

  • https://gin-gonic.com/en/docs/middleware/goroutines-inside-a-middleware/
  • https://gin-gonic.com/en/docs/server-config/context/
←Предыдущий вопросКак разбирать JSON-тело запроса в Gin с помощью `c.ShouldBindJSON()`?Следующий вопрос→Как определять маршруты в Gin? В чём разница между `gin.Default()` и `gin.New()`?

Связанные темы

Ginconcurrencycontext-propagationframework-internalsGIN

Частые вопросы на собеседовании

  • В каких backend-проектах Gin (Go framework) является сильным выбором, а где лучше выбрать более простой или другой стек?
  • Что такое система валидации Gin и как использовать struct tags для валидации входных данных?
  • Как писать unit-тесты для Gin-обработчиков с помощью httptest?
  • Как реализовать middleware аутентификации (JWT) в Gin?