https://github.com/gogo/protobuf больше не поддерживается https://github.com/gogo/protobuf/issues/691 (в настоящее время)
Это наша зависимость, несовместимая с новой версией golang/protobuf
, от которой зависит все больше и больше пакетов, поэтому нам нужно заменить версию golang/protobuf
, в зависимости от устаревших версий наших прямых зависимостей и, возможно, даже разбивать пакеты таким образом
gogo/protobuf
зависимость
Выяснить это
Выяснить, появится ли новый сопровождающий или другой плагин с паритетом функций?
Использовать только ванильный протобуф?
тесты
да
Плагин проверки, который мы используем, отказался от поддержки 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:
*ttnpb.EndDevice
(тип Go, сгенерированный ванилью) из реестра, десериализованный из сохраненных двоичных данных*ttnpb.EndDevice
в T_device
, (ПРИМЕЧАНИЕ: возможно, это может быть просто оболочка изначально или навсегда)T_device
внутри NST_device
в *ttnpb.EndDevice
(ПРИМЕЧАНИЕ: это может быть тривиальная, очень быстрая задача, если мы используем оболочку, поскольку нам нужно только изменить измененные поля, и это может быть выполнено даже в двоичном данные напрямую)*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 и другими.
Но я думаю, что есть шаги, которые мы можем предпринять уже сейчас:
Чтобы сохранить совместимость нашего 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, и чем дольше мы будем держать его открытым, тем больше у нас будет проблем при попытке обновить наши зависимости.
Нам действительно следует уделить этому больше внимания и принять решение о том, что мы собираемся со всем этим делать.
Запланируйте звонок на следующую неделю, чтобы мы могли обсудить его в автономном режиме.
Я думаю, мы должны пройти через этот болезненный процесс и сосредоточиться на решении этой проблемы через неделю или две. И чтобы избежать этого, мы делаем другие вещи, иначе это вызовет множество конфликтов. Чтобы иметь как можно больше рук, необходимо точно знать, что мы собираемся делать в каких случаях, как можно больше разделять задачи и следить за призом.
Следующие шаги:
unconvert
, gofumpt
и все остальное, что мы делаем поверх протокола.protoc-gen-gogottn
на protoc-gen-gofast
(или что-то похожее на ваниль)(gogoproto.*)
в наши файлы прототипов, чтобы они отображались так же, как сейчасgopls
и rf
.(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. Когда это будет сделано, пожалуйста, повторно добавьте других исполнителей, и давайте обсудим еще раз.
Самый полезный комментарий
Запланируйте звонок на следующую неделю, чтобы мы могли обсудить его в автономном режиме.
Я думаю, мы должны пройти через этот болезненный процесс и сосредоточиться на решении этой проблемы через неделю или две. И чтобы избежать этого, мы делаем другие вещи, иначе это вызовет множество конфликтов. Чтобы иметь как можно больше рук, необходимо точно знать, что мы собираемся делать в каких случаях, как можно больше разделять задачи и следить за призом.