Lorawan-stack: Изучите будущее плагина gogo proto

Созданный на 25 июн. 2020  ·  15Комментарии  ·  Источник: TheThingsNetwork/lorawan-stack

Резюме

https://github.com/gogo/protobuf больше не поддерживается https://github.com/gogo/protobuf/issues/691 (в настоящее время)

Почему нам это надо?

Это наша зависимость, несовместимая с новой версией golang/protobuf , от которой зависит все больше и больше пакетов, поэтому нам нужно заменить версию golang/protobuf , в зависимости от устаревших версий наших прямых зависимостей и, возможно, даже разбивать пакеты таким образом

Что там уже есть? Что ты видишь сейчас?

gogo/protobuf зависимость

Чего не хватает? Что вы хотите увидеть?

Выяснить это

Как вы предлагаете это реализовать?

Выяснить, появится ли новый сопровождающий или другой плагин с паритетом функций?
Использовать только ванильный протобуф?

Как вы предлагаете это проверить?

тесты

Можете ли вы сделать это самостоятельно и отправить запрос на слияние?

да

dependencies technical debt

Самый полезный комментарий

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

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

Все 15 Комментарий

Плагин проверки, который мы используем, отказался от поддержки GoGo
https://github.com/envoyproxy/protoc-gen-validate/pull/340

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

@rvolosatovs, вероятно, знает больше о настраиваемых параметрах, которые установлены в нашем генераторе gogottn , но вот что я нашел для явных параметров в наших файлах прототипа:

  • Мы могли бы начать с удаления параметров gogoproto.customname , gogoproto.stdtime и gogoproto.stdduration и goproto_enum_prefix . Их относительно легко удалить, поскольку компилятор Go немедленно сообщит о возникших проблемах.
  • Удаление опции gogoproto.embed будет означать, что мы больше не сможем получить доступ к встроенным полям (компилятор Go поможет нам найти их), и что сообщения больше не удовлетворяют некоторым интерфейсам (это может быть сложнее).
  • Опция gogoproto.nullable потребует гораздо больше работы, потому что нам придется начать использовать геттеры и добавить проверки на ноль. Компилятор Go может не уловить возникающие проблемы. Возможный обходной путь - временно сделать эти поля закрытыми, затем переписать их в геттеры / сеттеры и, наконец, снова сделать поля общедоступными.
  • Что будет довольно проблематично, так это поля, в которых используется gogoproto.customtype и перечисления, в которых используются параметры gogoproto.enum_stringer . Для тех, кто часто меняет способ маршалинга / демаршалинга в JSON. Для настраиваемых полей bytes таких как EUI, DevAddr и т. Д., Мы можем изменить тип (в протокольных сообщениях) на string (который совместим с двоичным кодом). Я боюсь, что с перечислениями это нарушит JSON API, поскольку они теперь принимаются (UnmarshalJSON) как строки, так и целые числа.

Может быть, это также хорошее время, чтобы начать думать о нашем API v4, потому что я могу представить, что мы можем обнаружить еще несколько (ломающих API) сюрпризов.

Я думаю, что лучше всего сначала попробовать https://github.com/alta/protopatch. В зависимости от результата:

  • Если все наши потребности удовлетворены -> выполните миграцию и забудьте об этом (нужно просто выполнить поиск и замену в каталоге api )
  • Если удовлетворены только некоторые из наших потребностей и есть настраиваемые параметры, не охватываемые плагином -> мы должны оценивать индивидуальные параметры и либо удалить эти настраиваемые параметры, либо, возможно, внести вклад в protopatch если это особенность с низким усилием. Это действительно зависит от варианта, хотя - если мы говорим о customtype - этот ИМО определенно оправдывает вклад, но, возможно, что-то вроде stdtime - не так уж и много.

Заглядывая вперед, я не думаю, что мы должны напрямую использовать ванильные протоколы protobuf в компонентах внутри во время выполнения (с учетом предоставленного сегодня набора функций protobuf).
Имеет смысл использовать protobuf только для (де-) сериализации, то есть для хранения и на уровне API. Однако внутренне использование простых ванильных протоколов Go для меня не имеет смысла.
Так, например, NS:

  1. получить *ttnpb.EndDevice (тип Go, сгенерированный ванилью) из реестра, десериализованный из сохраненных двоичных данных
  2. преобразовать *ttnpb.EndDevice в T_device , (ПРИМЕЧАНИЕ: возможно, это может быть просто оболочка изначально или навсегда)
  3. использовать T_device внутри NS
  4. преобразовать T_device в *ttnpb.EndDevice (ПРИМЕЧАНИЕ: это может быть тривиальная, очень быстрая задача, если мы используем оболочку, поскольку нам нужно только изменить измененные поля, и это может быть выполнено даже в двоичном данные напрямую)
  5. установить *ttnpb.EndDevice , сериализовать в двоичные данные

См. Также https://github.com/TheThingsNetwork/lorawan-stack/issues/342 (сгенерированные популяторы)

Я не сторонник (меньшей) альтернативы gogo. Такое ощущение, что толкаешь банку. Давайте сохраним все как можно более ванильным, особенно когда нам нужно снова решить, как лучше всего двигаться вперед.

Я согласен с тем, что мы можем рассмотреть возможность использования промежуточных типов в некоторых местах вместо того, чтобы полагаться везде на сгенерированные протоколы. По сути, он отделяет объекты передачи данных (DTO: protos, также для хранения) от объектов доступа к данным (DAO: как мы их используем). Если это в первую очередь чтение, мы также можем объявить интерфейсы и посмотреть, как далеко мы продвинемся с этим.

Тем не менее, я бы не стал менять весь NS на использование T_device , а скорее на конкретные структуры и / или интерфейсы по мере необходимости.

Перенесем это обсуждение на ноябрь

@rvolosatovs, что вы возражаете против перехода на ваниль с настраиваемым маршалером JSON?

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

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

Боюсь, что рефакторинг всей нашей кодовой базы будет проблемой, как бы мы это ни делали. Наши (сгенерированные gogo) прототипы сейчас используются повсюду (gRPC API, HTTP API, события, ошибки, внутри, Redis DB, ...), поэтому переход на что-то еще (что бы это ни было) коснется практически все, что есть в нашей кодовой базе, и то, как это выглядит сейчас, одновременно.

Жесткое требование состоит в том, чтобы мы не нарушали совместимость нашего API v3. Даже если мы решим использовать эту ситуацию как момент для начала работы над API v4 (по крайней мере, внутри), нам все равно придется поддерживать этот API v3 для существующих пользователей.

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

Но я думаю, что есть шаги, которые мы можем предпринять уже сейчас:

JSON

Чтобы сохранить совместимость нашего v3 JSON API, я думаю, что наша первая TODO - это работа над созданием маршалеров и демаршалеров JSON, которые понимают, как маршалировать / демаршалировать наши пользовательские типы. Я думаю, что делать это в любом случае разумно, потому что нет никаких обещаний стабильности для реализации Go формата JSON для буферов протокола , поэтому нам лучше контролировать это самим. Это также может позволить нам учитывать маски полей при маршалинге в JSON. Во время выполнения grpc-gateway мы можем регистрировать кодеки, поэтому мы можем просто написать кодек, который вызывает наши собственные (сгенерированные) (не) маршалеры вместо jsonpb {gogo, golang} / protobuf.

Генерация новых протоколов рядом со старыми

Я уже пробовал это здесь: https://github.com/TheThingsNetwork/lorawan-stack/commit/a41f62d98ae7ee719b576e6fcd2009a79cd38f4c

Это заставляет protobuf жаловаться на реестр типов, поэтому нам может потребоваться удалить golang_proto.RegisterType из наших старых протоколов, чтобы это работало. Удаление этого может потенциально нарушить разрешение google.protobuf.Any , но мы используем их только в ошибках и событиях, поэтому мы, вероятно, сможем найти обходные пути для этих конкретных случаев.

Создание функций для преобразования между старыми и новыми протоколами

Это только для переходного периода, но для долгосрочного решения мы хотели бы создать аналогичные преобразователи.

Обновляйте сервисы по очереди

Я уже пробовал это с помощью простого сервиса здесь: https://github.com/TheThingsNetwork/lorawan-stack/commit/cd7d75c8b42ad15eee1ac594ff6d0f2d5a75eb67 , но для более сложных сервисов нам определенно понадобятся эти конвертеры.

Обратите внимание, что это изменяет только сам сервис grpc. Шлюз grpc по-прежнему использует старый материал gogo на стороне JSON, а затем вызывает внутренний сервер gRPC, который затем запускает новую реализацию.

Здесь размещены некоторые начальные обновления зависимостей и обходные пути обратной совместимости: https://github.com/TheThingsNetwork/lorawan-stack/compare/issue/2798-codec

Все больше и больше наших зависимостей обновляются до protobuf 1.4 и V2 API, и чем дольше мы будем держать его открытым, тем больше у нас будет проблем при попытке обновить наши зависимости.

Нам действительно следует уделить этому больше внимания и принять решение о том, что мы собираемся со всем этим делать.

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

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

Следующие шаги:

  1. @rvolosatovs обновляет инструментарий, чтобы он был максимально приближен к «ванильному»:

    • Удалите такие вещи, как unconvert , gofumpt и все остальное, что мы делаем поверх протокола.

    • Переключитесь с protoc-gen-gogottn на protoc-gen-gofast (или что-то похожее на ваниль)

    • Явно добавьте параметры (gogoproto.*) в наши файлы прототипов, чтобы они отображались так же, как сейчас

  2. Нам нужно реорганизовать наш код, чтобы использовать геттеры вместо прямого доступа к полям. Возможно, в этом помогут такие инструменты, как gopls и rf .
  3. Мы начинаем удалять опции (gogoproto.*) одну за другой и обновляем код, который их использует. Возможно, в этом помогут такие инструменты, как gopls и rf .

    • Удаление gogoproto.populate и обновление тестов (https://github.com/TheThingsNetwork/lorawan-stack/issues/342)

    • Удаление gogoproto.customname и изменение EUI -> Eui и т. Д.

    • Удаление gogoproto.embed . Нам нужно убедиться, что сообщения по-прежнему реализуют интерфейсы, такие как ValidateContext(context.Context) error и ExtractRequestFields(m map[string]interface{}) .

    • Удалите gogoproto.nullable и убедитесь, что мы используем геттеры, где это возможно, в противном случае выполняем нулевые проверки.

    • ...

@rvolosatovs, давайте попробуем сделать эти первые шаги для v3.11.3. Когда это будет сделано, пожалуйста, повторно добавьте других исполнителей, и давайте обсудим еще раз.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги