Golang вопросы собеседований
13.5K subscribers
633 photos
4 videos
1 file
436 links
@notxxx1 - админ

@Golang_google - Golang для разработчиков

@itchannels_telegram - 🔥лучшие из ит

@golangl - chat

@golangtests - golang tests

@golang_jobsgo - go chat jobs

@ai_machinelearning_big_data - AI

@data_analysis_ml

РКН: clck.ru/3FmtKd
加入频道
👣 golang interview prep

Репозиторий, который создан для того, чтобы готовиться к собеседованию на Go на практике.

В данном репозитории находится рабочее CRUD-приложение, которое содержит множество ошибок, противоречащих современным стандартам, а также серьезные проблемы с безопасностью. Хороший вариант, чтобы попрактиковаться и исправить все ошибки.


🖥 Github

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 В чём разница между пакетами и модулями Golang?

Модуль - это дерево пакетов. Имя модуля задаётся в go.mod

Пакет - это набор исходных .go файлов, находящихся в одном каталоге и с одинаковой директивой package.

Файлы для одного пакета обязаны находиться в одном каталоге. Полное имя для пакета строится из имени модуля и пути к каталогу с файлами. Например,

в go.mod написано module example.org/mylib, тогда все пакеты из модуля example.org/mylib должны быть в дочерних каталогах относительно go.mod.
и путь к каталогу определяет имя пакета.
Например, в дереве исходников вашей библиотеки есть файлы в каталоге ./cmd/root.

Тогда эти файлы должны быть либо с директивой package root, либо package root_test. И полное имя пакета для этих файлов будет либо example.org/mylib/cmd/root, либо example.org/mylib/cmd/root_test[1].

Для автоматического поиска пакетов в Гугле придумали протокол goproxy Он реализован в GitHub, поэтому любой модуль, размещённый там, автоматически будет найден командами go get, go mod tidy, go build и подобными.

Но никто не ограничивает вас пользоваться только гитхабом. К примеру, поддержка goproxy есть в GitLab. Разворачиваете у себя на сервере гитлаб, настраиваете домены и прокси - и готово, go get начинает находить модули с вашим доменным именем.

На худой конец можно развернуть исходники стороннего модуля у себя в файловой системе, а в go.mod прописать зависимость с replace:

require example.org/some/module v1.01.02
replace example.org/some/module => ../some_module_src

В этом случае go build вообще не полезет в интернет, а возьмёт исходники модуля example.org/some/module из каталога ../some_module_src

[1] Пакет example.org/mylib/cmd/root_test должен содержать тесты для пакета example.org/mylib/cmd/root

#junior

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Вакансии направления Go – разрабатывай внутренние и B2B в Kaspersky!

Чем будете заниматься:
Golang developer (Sandbox) – разрабатывать микросервисы на Go, участвовать в создании нового функционала проекта и подготовке релизов новых версий продукта;
Go Developer (MSAP) – участвовать в разработке и поддержка бекенд сервисов под Linux/Kubernetes на Go;
Golang developer – участвовать в разработке микросервисов, работать с имеющимися проектами;
Golang developer (OSMP) – создавать бекенд сервисы под Linux/Kubernetes на Go, развивать микро-сервисный подход, писать тесты, проводить код-ревью.

Основные требования:
● опыт от 2х лет разработки на GO или другом языке (С++, С#, Java);
● опыт разработки микросервисов;
● опыт разработки под Linux;
● понимание принципов ООП.

Откликайтесь, даже если опыт частично отвечает требованиям. Возможно, у вас есть именно нужные нам навыки.
👣 Какие есть особенности синтаксиса получения и записи значений в map?

Ответ:
Получить значение из map, которую мы предварительно не аллоцировали нельзя, приложение упадет в панику.

Если ключ не найден в map в ответ мы получим дефолтное значение для типа значений map. То есть, для строки - это будет пустая строка, для int - 0 и так далее. Для того, чтобы точно понять, что в map действительно есть значение, хранящееся по переданному ключу, необходимо использовать специальный синтаксис. А именно, возвращать не только само значение, но и булевую переменную, которая показывает удалось-ли получить значение по ключу.


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Расскажите про утечки памяти в. Go Для чего используется инструмент pprof?

Ответ
Утечки памяти в Go могут принимать разные формы.

Обычно мы считаем, что это баги, однако истинная причина проблем может быть заложена ещё на стадии проектирования.

Приведем распространённые примеры появления проблем с памятью:
• неверное представление данных;
• интенсивное применение рефлексии либо строк;
• применение глобальных переменных;
• бесконечные горутины.


Самый простой способ создать утечку памяти в Go — определить глобальную переменную, массив, и добавить в него данные.

Golang предлагает инструмент с именем pprof. Он может помочь обнаружить проблемы с памятью. Он также может быть использован при обнаружении проблем в работе процессора.

нструмент pprof создаёт файл дампа, куда кладёт сэмпл кучи. Данный файл вы сможете в итоге проанализировать/визуализировать, чтобы позволит получить карту:
• текущего выделения памяти;
• накопительного (общего) выделения памяти.

Кроме того, у pprof есть возможность сравнивать снимки, которые сделаны в разное время. Это бывает полезно при определении проблемных областей кода при стрессовых сценариях.

Профили pprof
Инструмент pprof функционирует с помощью профилей. Под профилем понимается набор трассировок стека, которые показывают последовательности вызовов, ставших причиной появления определённого события, к примеру, выделения памяти. Подробная информация о реализации профилей содержится в файле runtime/pprof/pprof.go.

Язык программирования Go имеет целый перечень встроенных профилей, которые вы можете применять в стандартных ситуациях:
• goroutine — следы всех текущих горутин;
• allocs — выборка всех предыдущих выделений памяти;
• heap — выборка выделений памяти живых объектов;
• threadcreate — следы стека, ставшие причиной создания новых потоков в ОС;
• mutex — следы стека держателей конфликтующих мьютексов;
• block — следы стека, ставшие причиной блокировки примитивов синхронизации.


Heap
Heap (куча) представляет собой абстрактное представление места, в котором ОС хранит объекты, использующие код. В дальнейшем эта память очищается сборщиком мусора либо освобождается вручную.

Однако куча не является единственным местом
, где осуществляется выделение памяти — часть памяти выделяется и на стеке. В языке программирования Go стек обычно используют для присвоений, которые происходят в рамках работы функции. Также в Go используется стек в случае, когда компилятор «знает», сколько конкретно памяти надо зарезервировать перед выполнением (к примеру, для массивов фиксированного размера).

При этом данные кучи должны быть освобождены с применением сборки мусора, а вот данные стека — нет. Именно поэтому гораздо эффективнее применять стек там, где это представляется возможным.

Получаем данные кучи посредством pprof
Существуют 2 основных способа получить данные. Первый, как правило, применяют в качестве части теста — он включает импорт runtime/pprof с последующим вызовом pprof.WriteHeapProfile(some_file) в целях записи информации в кучу.

// Функция lookup() берёт профиль
namepprof.Lookup("heap").WriteTo(some_file, 0)


Здесь WriteHeapProfile() существует для обратной совместимости. Однако прочие профили таких возможностей не имеют, поэтому для получения данных профилей вам следует применять функцию Lookup().

Другой способ — пустить его через HTTP (по web-адресу). Этот способ позволяет извлекать определённые данные из запущенного контейнера в тестовой среде либо e2e-среде или даже из production. При этом всю документацию пакета pprof вы можете и не читать, но как его включить, вы знать должны.

import (
"net/http"
_ "net/http/pprof"
)

...

func main() {
...
http.ListenAndServe("localhost:8080", nil)
}


Напишите в комментариях какие альтернативы pprof вам известны
👇

#junior

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥 Полный курс Golang разработчика 2023 года. Часть1.

1. О курсе - https://www.youtube.com/watch?v=Nv0vmR5OqRg&t=34s

2. Установка GO - https://www.youtube.com/watch?v=gi6gAhzUhUg

3. Пакеты в Golang https://www.youtube.com/watch?v=RNVhf-zBpdQ

4. Типы данных в Go - https://www.youtube.com/watch?v=_ilP500FEP8&t=16s

5. Строки и руны - https://www.youtube.com/watch?v=wUQB74nNxos&t=27s

6. Инструменты CLI- https://www.youtube.com/watch?v=LzqVFx6yOAs&t=8s

7. Введение в переменные - https://www.youtube.com/watch?v=zQa85CrYQJ4&t=190s

8. Переменные на практике - https://www.youtube.com/watch?v=P9Lk0EiO2pU&t=1s

9. Упражнения с переменными -

https://www.youtube.com/watch?v=huj6RHQC34I&t=1s

10. Работа с функциями - https://www.youtube.com/watch?v=euudha7zAiU&t=7s

11. Функции на практике - https://www.youtube.com/watch?v=YdoMOD6H_nk

12. Управление потоками с операторами if else - https://www.youtube.com/watch?v=Mq6WQy_eq_k&t=1s

13. Оператор Switch
- https://www.youtube.com/watch?v=4REsob985vc

14. Циклы - https://www.youtube.com/watch?v=gpt8IGahbXo

15. Структуры - https://www.youtube.com/watch?v=VrOflBI4f_E&t=311s

16. Массивы - https://www.youtube.com/watch?v=QrVHFGtCAnE

17. Срезы - https://www.youtube.com/watch?v=XA1WFY1kv2o&t=671s

18. Карты - https://www.youtube.com/watch?v=XA1WFY1kv2o&list=PLysMDSbb9HcxpAb8lhnMaRpX890wSLz66&index=18

19.Указатели - https://www.youtube.com/watch?v=LYFOJhP28Ro

20. Методы - https://www.youtube.com/watch?v=hmWwp04_XC0

21. IOTA - https://www.youtube.com/watch?v=La67BqQdoys

22.FMT - https://www.youtube.com/watch?v=-Ie4-R23VTk

23.INIT - https://www.youtube.com/watch?v=riIi-FpSOuc

24 Тесты- https://www.youtube.com/watch?v=AprUuq_rm0I

25 Интерфейсы - https://www.youtube.com/watch?v=Amun1J6KE3Q&t=70s

26. Обработка ошибок - https://www.youtube.com/watch?v=VTmHbN0Y4aU

Полный плейлист

📌Курс на stepik

Полный плейлист - https://www.youtube.com/watch?v=XyVihrOSN80&list=PLysMDSbb9HcxpAb8lhnMaRpX890wSLz66&index=19

📌Курс на stepik

@golang_interview
👣 Описание наиболее важных обновление последней версии Go.

go install golang.org/dl/go1.21rc2@latest
~/go/bin/go1.21rc2 download
export GOROOT=/Users/jason/sdk/go1.21rc2/

https://www.dolthub.com/blog/2023-07-07-golang-1.21-release/


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Как масштабировать контейнер?

В облачной среде количество людей, использующих программное приложение, может вырасти. Интервьюер может использовать этот вопрос, чтобы проверить вашу способность изменять контейнеры Docker для эффективного управления растущим приложением. Вы можете ответить на этот вопрос, объяснив процесс, которому вы следуете при масштабировании контейнера Docker.

Пример: Системные администраторы могут масштабировать контейнеры Docker, изменяя количество контейнеров или количество ресурсов, выделяемых каждому контейнеру. Чтобы изменить количество контейнеров, можно использовать команду 'docker-compose up' с флагом '--scale'.

Чтобы настроить количество ресурсов, можно использовать команду docker run с флагами '--memory' и '--cpu-shares'. Ограничением, которое может возникнуть в процессе масштабирования, является память. Для успешного масштабирования пакета Docker контейнеру может потребоваться достаточно памяти, чтобы справиться с возросшей вычислительной мощностью.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Какая сложность у следующего
алгоритма?

func reverse(n []int) {
length := len(n)

for i := 0; i < length / 2; i++ {
other := length - i - 1
temp := n[i]

n[i] = n[other]
n[other] = temp
}
}

func reverse(n []int) {
for n / 2 раз
}


Думаете O(log n)? Казалось бы да, но нет.

Ответ: O(n/2), т.к. мы просто один раз берем половину элементов массива и итерируем их, скажем было 100 элементов взяли половину - 50, для Big O это все те же n элементов, следовательно сложность алгоритма O(n)


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Что такое fuzzing-тестирование? Как устроен Fuzzing в Go?

Fuzzing — это технология автоматизированного поиска ошибок с помощью случайных входных данных и анализа реакции программы на них.

Технология полезна, если нужно проверить граничные условия или корректность обработки потока ввода — то есть тогда, когда нужно найти значения, при которых «падает» программа.

В стандартном фреймворке для тестирования есть специальные типы тестов — Test и Benchmark.

В первой конструкции (картинка) мы объявляем фреймворку, в каких случаях тест можно считать успешным, а в каких — провальным. Во второй — фреймворк пытается подобрать такое количество итераций, на котором можно достаточно точно измерить среднее время выполнения одной итерации. По сути, Fuzzing объединяет Test и Benchmark.

Внутри функции FuzzFoo мы сообщаем, в каких случаях тест является провальным, а также просим тестовый фреймворк сгенерировать случайные данные нужных типов — в контексте примера это число и строка.

Вот ключевые моменты, которые важно запомнить для подготовки fuzzing-тестов:

- Название метода нужно записывать через приставку Fuzz — например, FuzzTest, FuzzBug или FuzzFoo. Иначе Go инициализирует обычный unit-тест.

- В качестве параметра необходимо передать указатель на testing.F. Этот параметр нужен, чтобы «связать» тест с кодом программы.

@golang_interview
Вакансия: Golang Developer  Компания: Lamoda Tech
Формат: удаленный или гибридный
Занятость: полная занятость

В Lamoda Tech мы делаем моду ближе для миллионов пользователей. Наша команда совершает цифровую революцию в fashion и e-commerce.

Приглашаем в нашу команду Golang разработчиков!


Основные требования

- опыт коммерческой разработки бэкенда на Golang от 2-х лет;
- опыт работы с SQL базами данных
- умение проектировать API сервисов;
- опыт работы с нереляционными базами данных
- опыт работы с Docker
- опыт работы с Git

Мы предлагаем

- работу в гибридном режиме — можно приезжать в офис или работать из дома
- бесплатные сессии с коучами и психологами
- оплату участия в профессиональных конференциях
- ноутбук и другая необходимая техника для работы
- ДМС с первого месяца, со стоматологией и чек-апом здоровья раз в год;
- Ежемесячные промокоды на Lamoda до 25%;
- офис на Полежаевской с йогой, тренажерным залом и капсулой сна, а также коворкинг в центре Санкт-Петербурга.

Узнать больше
👣 Modern Go Application

В этом репозитории собраны лучшие практики разработки приложений на языке Go. В дополнение к деталям, относящимся к конкретному языку, в нем также реализованы различные практики, которые подходят для работки на любом языке.

Github

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Тестовое задание на разработки балансировщика нагрузки на Go

В данном случае используется довольно простой алгоритм Round-Robin.

Начнем с базового объекта server, который содержит 3 атрибута, связанных с сервером

Address()
IsAlive()
Функция Serve() для работы с запросами

type Server interface {
Address() string
IsAlive() bool
Serve(rw http.ResponseWriter, req *http.Request)
}


В дальнейшем используется второй тип объекта – simpleServer.

type simpleServer struct {
addr string
proxy *httputil.ReverseProxy
}


После определения методов, используемых в указанных объектах, мы создаем loadbalancer вместе с функцией getNextAvailableServer().
func NewLoadBalancer(port string, servers []Server) *LoadBalancer {
return &LoadBalancer{
port: port,
roundRobinCount: 0,
servers: servers,
}
}


func (lb *LoadBalancer) getNextAvailableServer() Server {
server := lb.servers[lb.roundRobinCount%len(lb.servers)]
for !server.IsAlive() {
lb.roundRobinCount++
server = lb.servers[lb.roundRobinCount%len(lb.servers)]
}
lb.roundRobinCount++
return server
}


Вызываем main()
func main() {
servers := []Server{
newSimpleServer("https://snapcraft.io"),
newSimpleServer("https://github.com/sambhavsaxena"),
newSimpleServer("http://localhost:3001"),
}
lb := NewLoadBalancer("3000", servers)
handleRedirect := func(rw http.ResponseWriter, req *http.Request) {
lb.serveProxy(rw, req)
}
http.HandleFunc("/", handleRedirect)
fmt.Printf("distributing requests fired at 'localhost:%s'\n", lb.port)
http.ListenAndServe(":"+lb.port, nil)
}


Статья
Полный код

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Изменение порядка следования элементов связного списка

Сложность: Средняя

Условие задачи : дан связный список:
L0 → L1 → … → Ln - 1 → Ln.

Надо переопределить порядок следования элементов на следующий:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

Пример:

Ввод: head = [1,2,3,4]
Вывод: [1,4,2,3]

Ввод: [1,2,3,4,5]
Вывод: [1,5,2,4,3]

Решение задачи

Пишите свое решение в комментариях👇

@golang_interview
⚡️Маст-хэв список для программистов, каналы с последними книжными новинками, библиотеками, разбором кода и актуальной информацией, связанной с вашим языком программирования.
Лучший способ получать свежие обновлении и следить за трендами в разработке.

Python: t.me/pythonl
C#: t.me/csharp_ci
C/C++/ t.me/cpluspluc
Машинное обучение: t.me/ai_machinelearning_big_data
Data Science: t.me/data_analysis_ml
Devops: t.me/devOPSitsec
Go: t.me/Golang_google
Базы данных: t.me/sqlhub
Rust: t.me/rust_code
Javascript: t.me/javascriptv
React: t.me/react_tg
PHP: t.me/phpshka
Android: t.me/android_its
Мобильная разработка: t.me/mobdevelop
Linux: t.me/+A8jY79rcyKJlYWY6
Big Data: t.me/bigdatai
Хакинг: t.me/linuxkalii
Java: t.me/javatg

💼 Папка с вакансиями: t.me/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: t.me/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: t.me/addlist/eEPya-HF6mkxMGIy

📕 Бесплатные Книги для программистов: https://yangx.top/addlist/YZ0EI8Ya4OJjYzEy

🎞 YouTube канал: https://www.youtube.com/@uproger

😆ИТ-Мемы: t.me/memes_prog

🇬🇧Английский: t.me/english_forprogrammers
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Расскажите про шаблон проектирования Стратегия? Приведите пример реализации на Go.

Стратегия (. Strategy) — поведенческий шаблон проектирования, предназначенный для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Это позволяет выбирать алгоритм путём определения соответствующего класса. Шаблон Стратегия (. Strategy) позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.

Реализация шаблона представлена на кратинке.

В примере у объекта toy есть DialogueReciter, который является интерфейсом, и это важно, поскольку мы хотим, чтобы поведение объекта-игрушки можно было изменять во время выполнения программы. Если бы это был не интерфейс, а конкретный тип, то мы могли бы присвоить объекту-игрушке только поведение этого конкретного типа.

Поведение для объекта toy определено в интерфейсе, а фактическая реализация поведения, например, Recite, выполняется отдельно различными конкретными типами, например, SpiderMan, SuperMan и BatMan.

Если бы поведение toy было закодировано в конкретном типе, то мы были бы заблокированы на использование только этого конкретного поведения.

Поэтому можно сказать, что "программируй под интерфейс, а не под реализацию", и это важный принцип проектирования.
"Паттерн стратегии" определяет семейство алгоритмов,
инкапсулирует каждый из них и делает их взаимозаменяемыми.

Стратегия позволяет алгоритму изменяться независимо от
клиентов, которые его используют".

Пишите свой пример реализации шаблона в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Experimenting with project templates

Когда вы начинаете новый проект на Go, вы можете начать с клонирования существующего проекта. Таким образом, вы можете начать с уже работающего проекта, внося в него постепенные изменения, а не начинать с нуля.

Gonew - экспериментальный инструмент для создания новых проектов на языке Go на основе предопределенных шаблонов. Любой программист может написать шаблоны, которые упаковываются и распространяются как модули.

Начните с установки gonew с помощью go install:

$ go install golang.org/x/tools/cmd/gonew@latest

Чтобы скопировать существующий шаблон, запустите gonew в родительском каталоге нового проекта с двумя аргументами: первый - путь к шаблону, который необходимо скопировать, второй - имя модуля создаваемого проекта. Например:

$ gonew golang.org/x/example/helloserver example.com/myserver
$ cd ./myserver


А затем вы можете читать и редактировать файлы в ./myserver для настройки.

Для начала мы написали два шаблона:

hello: Инструмент командной строки, печатающий приветствие, с флагами настройки.
helloserver: HTTP-сервер, передающий приветствия.

https://go.dev/blog/gonew

Еще примеры: https://github.com/GoogleCloudPlatform/go-templates

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Расскажите про внутреннее устройство mutex

Мьютекс гораздо более комплексная структура по сравнению с atomic, чем может показаться на первый взгляд. Прежде всего у нас есть два вида мютексов: sync.Mutex и sync.RWMutex. У каждого из них есть методы Lock и Unlock, у RWMutex есть дополнительно метод RLock (блокирование для чтения). В обоих типах методы Lock довольно долгие по сравнению с атомиками.

У Mutex код метода Lock включает два вида блокировки. Первый вариант - это когда удается захватить не заблокированный мьютекс, второй вариант довольно долгий и он запускается если мьютекс заблокирован:

// Lock locks m.
// If the lock is already in use, the calling goroutine
// blocks until the mutex is available.
func (m *Mutex) Lock() {
// Fast path: grab unlocked mutex.
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
if race.Enabled {
race.Acquire(unsafe.Pointer(m))
}
return
}
// Slow path (outlined so that the fast path can be inlined)
m.lockSlow()
}

Первый вариант довольно быстрый и включает в себя одну atomic операцию. Второй вариант включает довольно много кода и здесь подробно разбираться не будет: там также используются атомики в процессе блокировки, но очевидно, что он исполняется еще дольше первого варианта (Fast path).

У RWMutex код метода Lock включает в себя вызов метода Lock структуры Mutex:

// Lock locks rw for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (rw *RWMutex) Lock() {
if race.Enabled {
_ = rw.w.state
race.Disable()
}
// First, resolve competition with other writers.
rw.w.Lock()
// Здесь пропущена часть кода ...
}
}

Да и сама структура RWMutex включает в себя структуру Mutex как одно из полей:

type RWMutex struct {
w Mutex // held if there are pending writers
// Здесь пропущена часть кода ...
}


Метод RLock у RWMutex гораздо быстрее и содержит меньше кода, но тем не менее не быстрее атомика, который там задействован:

func (rw *RWMutex) RLock() {
// Здесь пропущена часть кода ...
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
// A writer is pending, wait for it.
runtime_SemacquireMutex(&rw.readerSem, false, 0)
}
//


📌Вопрос что производительнее атомики или мьютексы?

Напишите свой ответ в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Для чего нужен тип http.ResponseController?

http.ResponseController:
Позволяет переопределять ваши общесерверные таймауты/дедлайны чтения и записи новыми для каждого отдельного запроса.

Шаблон использования интерфейсов http.Flusher и http.Hijacker стал более понятным и менее сложным. Нам больше не нужны никакие утверждения типов!

Он делает проще и безопаснее создание и использование пользовательских реализаций http.ResponseWriter.

Таймауты для отдельных запросов
http.Server Go имеет настройки ReadTimeout и WriteTimeout, которые вы можете использовать для автоматического закрытия HTTP-соединения, если время, затраченное на чтение запроса или запись ответа, превышает какое-либо фиксированное значение. Эти настройки являются общесерверными и применяются ко всем запросам, независимо от обработчика или URL.

С появлением http.ResponseController можно использовать методы SetReadDeadline() и SetWriteDeadline(), чтобы ослабить или, наоборот, ужесточить эти настройки для каждого конкретного запроса в зависимости от ваших потребностей. Например:

func exampleHandler(w http.ResponseWriter, r *http.Request) {
rc := http.NewResponseController(w)

// Установим таймаут записи в 5 секунд.
err := rc.SetWriteDeadline(time.Now().Add(5 * time.Second))
if err != nil {
// Обработка ошибки
}

// Делаем здесь что-нибудь...

// Записываем ответ как обычно
w.Write([]byte("Done!"))
}

Это особенно полезно для приложений, содержащих небольшое количество обработчиков, которым требуются более длительные таймауты, чем всем остальным, для таких вещей, как обработка загрузки файла или выполнение длительной операции.

Несколько деталей, о которых стоит упомянуть:

Если вы установите очень короткий общесерверный таймаут, и этот таймаут будет достигнут до того, как вы вызовете SetWriteDeadline() или SetReadDeadline(), то они не возымеют никакого эффекта. Общесерверный таймаут в этом случае побеждает.

Если базовый http.ResponseWriter не поддерживает установку таймаутов для отдельных запросов, то вызов SetWriteDeadline() или SetReadDeadline() вернет ошибку http.ErrNotSupported.

Теперь можено отменять общесерверный таймаут для отдельных запросов, передав обнуленную структур time.Time в SetWriteDeadlin() или SetReadDeadline(). Например:

rc := http.NewResponseController(w)
err := rc.SetWriteDeadline(time.Time{})
if err != nil {
// Обработка ошибки
}

Интерфейсы Flusher и Hijacker
Тип http.ResponseController также делает более удобным использование «опциональных» интерфейсов http.Flusher и http.Hijacker. Например, до Go 1.20, чтобы отправить данные ответа клиенту, вы могли использовать кода следующего вида:

func exampleHandler(w http.ResponseWriter, r *http.Request) {
f, ok := w.(http.Flusher)
if !ok {
// Обработка ошибки
}

for i := 0; i < 5; i++ {
fmt.Fprintf(w, "Write %d\n", i)
f.Flush()

time.Sleep(time.Second)
}
}

Теперь можно сделать это так:

func exampleHandler(w http.ResponseWriter, r *http.Request) {
rc := http.NewResponseController(w)

for i := 0; i < 5; i++ {
fmt.Fprintf(w, "Write %d\n", i)
err := rc.Flush()
if err != nil {
// Обработка ошибки
}

time.Sleep(time.Second)
}
}
Шаб
лонный код перехвата (hijacking) соединения аналогичен:

func (app *application) home(w http.ResponseWriter, r *http.Request) {
rc := http.NewResponseController(w)

conn, bufrw, err := rc.Hijack()
if err != nil {
// Обработка ошибки
}
defer conn.Close()

// Делаем здесь что-нибудь...
}

Опять же, если ваш базовый http.ResponseWriter не поддерживает flush или перехват соединения, то вызов Flush() или Hijack() в http.ResponseController также вернет ошибку http.ErrNotSupported.

Теперь также проще и безопаснее создавать и использовать пользовательские реализации http.ResponseWriter, которые поддерживают flush и перехват соединения.

Приведите пример с кодом реализации своей http.ResponseWriter в комментариях 👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM