Задать вопрос
  • Как можно измерить производительность http сервера?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    После этого уже можно будет продолжить искать причину
  • Как можно измерить производительность http сервера?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    выполните ab -v 4 http://localhost:3000/, чтобы убедиться, что получаете верное содержимое ответа, чтобы быть на 100% уверенным, что отвечает именно сервер Go
    Должно быть что-то подобное
    ---
    GET / HTTP/1.0
    Host: localhost:11223
    User-Agent: ApacheBench/2.3
    Accept: */*
    
    
    ---
    LOG: header received:
    HTTP/1.0 200 OK
    Date: Tue, 28 Dec 2021 14:29:27 GMT
    Content-Length: 5
    Content-Type: text/plain; charset=utf-8
    
    Hello
    LOG: Response code = 200
    ..done
  • Как можно измерить производительность http сервера?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Вы тестируете этот скрипт?
    Если да - тогда запрос приходит куда-то не туда (не в Go сервер), у вас Document Length должен быть 5 байт (Hello), а у вас 1754 байта. Но что-то ооочень медленно.
  • В чем сложность поддержки проектов на Go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Тут просто зависит от задачи, требований, наличия ресурсов.

    Если предполагается нагрузка или большой/сложный проект - использую Go.

    Если нужно сделать что-то простое, легко дорабатываемое (легко найти специалиста) - использую Python + FastAPI/SQLAlchemy, иногда Python + Django (если что-то совсем простое).

    PHP, Ruby on rails тоже, в целом, для таких проектов подойдут. Я с ними тоже работал, но по итогу остановился на Python, т.к. код хорошо читается (лучше PHP, JS, Ruby) на мой взгляд, библиотек хороших много, людей, которые его знают очень много, популярность растёт - значит и дальше будет развиваться.

    PHP использую когда нужно сделать лендинг, идеально для этого подходит )))
  • Как сделать grpc middleware для метрики времени коннекта?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Я с gRPC особо не работал, не уверен, что эту задачу получится решить с помощью middleware.
    Если бы у меня стояла такая задача, я бы сначала разобрался как отлавливать connect/disconnect.
    Вот тут есть пример https://github.com/grpc/grpc-go/issues/3634, но не уверен на 100%
    А после того, как станет понятно как эту информацию получить - станет понятно как эту метрику отдавать.
  • В чем сложность поддержки проектов на Go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Выбор всегда должен быть осознанный, иначе проблем не избежать.

    Если вы заказываете выполнение проекта, например, с оплатой за проект или у вас в штате один программист - в этом случае нужно рассматривать только самые популярные языки в связке с самыми популярными фреймворками, например Python + Django/Flask, PHP + Laravel и т.д.
    Иначе вы неизбежно получите именно ту проблему о которой вы написали.

    Плюс нужно требовать документацию и покрытие тестами без этого новый программист будет обречён на создание новых проблем и будет настаивать на том, что всё надо переписать :)
    Но на это нельзя соглашаться если проект хоть как то работает, иначе вы получите опять тот же самый результат. Исключение только то, что переделывать будут уже под Python Django/Flask, PHP + Laravel.

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

    Если у вас уже есть рабочий продукт, который не справляется с нагрузками или вы сразу понимаете что у вас будут большие нагрузки (например вы Ozon/Avito/Yandex и т.д.) или по каким то другим причинам вам не можете использовать скриптовые языки с популярными фреймворками - несомненно Go будет хорошим выбором.
  • В чем сложность поддержки проектов на Go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    > Сообщения в телеграмм?
    В каких то случаях да, в каких то почта.

    NodeJS - это да :))
  • В чем сложность поддержки проектов на Go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    У меня в этом плане сделано попроще, как мне кажется :)
    Подобный подход я использовал еще когда писал на C.

    Фактически есть структура вида, которая реализует интерфейс error
    type Error struct {
        Code       uint64   `json:"code"`
        Message string    `json:"message"`
    }


    Все функции, которые могут вернуть ошибку - возвращают именно эту структуру.

    При реализации я ставил себе такие задачи:
    - иметь возможность однозначно идентифицировать ошибку
    в папке core в проекте есть файл где константами описаны общие коды ошибок

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

    - иметь возможность изменять текст ошибки в ответе пользователю для низкоуровневых ошибок, например при запросе к базе

    Вот почти полная реализация
    // Error тип ошибки, который содержит сообщение и код ошибки
    type Error struct {
        Code       uint64   `json:"code"`
        Message string `json:"message"`
    }
    
    // Alias алиас для json маршалинга
    type Alias Error
    
    // New создаёт структуру Error
    func New(code uint64, message string) *Error {
        return &Error{
            Code:    code,
            Message: message,
        }
    }
    
    // Newf создаёт структуру Error, для формирования сообщения вызывает Sprintf
    func Newf(code uint64, format string, args ...interface{}) *Error {
        return &Error{
            Code:    code,
            Message: fmt.Sprintf(format, args...),
        }
    }
    
    // NewIfNotNil создаёт структуру Error если err != nil
    func NewIfNotNil(code uint64, err error) *Error {
        if err == nil {
            return nil
        }
    
        return New(code, err.Error())
    }
    
    // Error реализация интерфейса error
    func (e Error) Error() string {
        return e.Message
    }
    
    // String реализация интерфейса Stringer
    func (e Error) String() string {
        return e.Message
    }
    
    // MarshalJSON реализует интерфейс json.Marshaler
    func (e Error) MarshalJSON() ([]byte, error) {
        return json.Marshal(Alias(e))
    }
    
    // UnmarshalJSON реализует интерфейс json.Unmarshaler
    func (e *Error) UnmarshalJSON(data []byte) error {
        if data == nil || string(data) == "null" {
            return nil
        }
        err := (*Alias)(e)
        return json.Unmarshal(data, &err)
    }


    А дальше что-то типа такого
    func myFunc1() *errno.Error {
        err := doSomthing(...)
        if err != nil {
            return errno.New(core.ErrCodeDBError, err.Error())
        }
    }
    
    // или тоже самое, но в одну строку
    func myFunc2() *errno.Error {
        // если функция doSomthing вернёт nil - вернёт nil
        // если doSomthing вернёт ошибку - создаст структуру с кодом ошибки core.ErrCodeDBError и сообщением
        // и вернёт *errno.Error
        return errno.NewIfNotNil(core.ErrCodeDBError, doSomthing(...))
    }


    Есть еще обёртка, которая отправляет мне оповещение, когда происходит ошибка, ну... конечно кроме 401 и т.д.
    Если что-то происходит не так, как надо - я об этом узнаю до того, как кто-то об этом скажет :)

    Отдельно есть еще обработка panic.
    Если где-то вылетает panic мне отправляется письмо с дампом:
    - настроек/переменных окружения
    - параметров HTTP запроса
    - cookies
    - stack trace

    Пока такой подход мне полностью подходит.
    Если у вас есть случаи, когда такой подход не подходит - напишите пожалуйста, мне будет очень интересно о них узнать.
  • Что выбрать для телеграм бота? Вебхуки или лонгполлинг?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    nakem, тут всё точно так же как и с обычными HTTP запросами, только в привычном варианте HTTP запрос приходит от пользователя/клиента, а в случае телеграм бота - запрос приходит с телеграм сервера, но это всё тот же HTTP запрос.

    Т.е. достаточно просто запустить сервис бота на разных серверах и, например, nginx'ом балансировать трафик между ними.
  • Что выбрать для телеграм бота? Вебхуки или лонгполлинг?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Dmitrii, это явно проблема на стороне бота, как один из вариантов - могло разрываться соединение с базой, и при новом запросе с телеграм скрипт понимал, что соединение оборвано, пытался восстановить и т.д.
  • Как в gorilla mux сделать серверную мидлвару?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Рад помочь :)
    Допишу этот комментарий в ответ, чтобы если кому то еще понадобится - не искали в комментариях :)
  • Как в gorilla mux сделать серверную мидлвару?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Есть еще один вариант, скорее всего это прям то, что нужно

    https://pkg.go.dev/net/http/httptest#ResponseRecorder, я его использовал ранее для написания тестов.

    Пример будет примерно таким
    func (m *LoggingMiddleware) LogBody(next http.Handler) http.Handler {
        fn := func(w http.ResponseWriter, r *http.Request) {
            wRecorder := httptest.NewRecorder()
            next.ServeHTTP(wRecorder r)
            resp := wRecorder.Result()
            body, _ := io.ReadAll(resp.Body)
            // не забыть записать ответ в w
        }
    
        return http.HandlerFunc(fn)
    }


    Пример его использования из официальной документации https://pkg.go.dev/net/http/httptest#example-Respo...
  • Нужен ли Nginx для веб приложения на Golang?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Всё верно, статику можно и без Nginx.

    При желании, можно сделать поддержку разных доменов на Go, но это не целесообразно, когда уже есть готовый Nginx.

    Еще, как вариант, когда нужно не просто несколько доменов разных, а, например, когда у вас есть ваше API на Go, а админка у проекта, например на Python+Django, тогда статику нет смысла раздавать Go, т.к. вам всё равно придётся ставить Nginx, либо делать реализацию проксивания к админке самостоятельно (средствами Go).

    Или у вас API на Go, а надо еще чтобы, какой нибудь, PHPMyAdmin работал, или система мониторинга висела на том же сервере и т.д., в этом случае также раздавать статику на Go - это бессмысленная трата ресурсов.
  • Как разрешить вызов api контроллера, только одному серверу по ip (который отправляет вебхук)?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    На вашей стороне ничего не поменяется

    Вот так будет выглядеть запрос
    https://pkg.go.dev/net/http#Request

    В запросе есть поле URL, вот так выглядит
    https://pkg.go.dev/net/url#URL
  • Как понять причину отмененного контекста?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Сейчас нет возможности внимательно изучить код.
    При беглом изучении кода - я бы искал ошибку в функциях
    h.processIncomingAudioChunks, h.processBackendResponses
    По возможности скиньте их код, без кода я точно не найду там ошибку ))

    Предполагаю, что вам на вход приходит аудио, вы это аудио разбиваете на части и каждую часть в отдельной горутине обрабатываете.
    Если я правильно понял - тогда в такой ситуации, контекст cancel должен вызываться если при обработке одной из частей произошла ошибка и обработка оставшихся частей уже теряет смысл.
    Т.е. какая то из этих функций вызывает cancel(). Если нет данных по ошибке, возможно неверная логика при вызове cancel.

    В общем я бы начал искать ошибку в этих функциях, проверяйте логику начиная с мест, где есть вызов cancel()
  • Куда и как добавить асинхронность в телеграм бота?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Это всё делает планировщик Go.
    Вам не нужно об этом думать, ваша основная задача убедиться, что не будет коллизии данных.
    В вашем коде я вижу только то, о чём писал выше.

    Если два разных пользователя вызовут /start одновременно - при условии, что у вас один процессор и одно ядро - запросы обработаются по очереди на этом ядре, если же ядер больше и вы указали их использовать - тогда запросы должны обработаться параллельно, при этом они друг-другу не мешают.

    Если всё же не сложилась картина - напишите мне в телеграм, можно будет созвониться