Lorawan-stack: التحقيق في مستقبل البرنامج المساعد gogo proto

تم إنشاؤها على ٢٥ يونيو ٢٠٢٠  ·  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 ، حيث يتم قبولها الآن (بواسطة UnmarshalJSON) كسلاسل و ints.

ربما يكون هذا أيضًا وقتًا مناسبًا لبدء التفكير في الإصدار 4 API الخاص بنا ، لأنني أستطيع أن أتخيل أننا قد نكتشف المزيد من المفاجآت (كسر واجهة برمجة التطبيقات).

أعتقد أن أفضل طريقة للمضي قدمًا هي تجربة https://github.com/alta/protopatch أولاً

  • إذا تمت تغطية جميع احتياجاتنا -> ترحيل ونسيان هذا (يجب أن يكون مجرد بحث واستبدال في دليل api )
  • إذا تمت تغطية بعض احتياجاتنا فقط وكانت هناك خيارات مخصصة لا يغطيها المكون الإضافي -> يجب علينا التقييم على أساس كل خيار وإما إزالة هذه الخيارات المخصصة أو ربما المساهمة في protopatch إذا كان ميزة منخفضة الجهد. هذا يعتمد حقًا على الخيار ، على الرغم من - إذا كنا نتحدث عن customtype - فإن IMO تبرر بالتأكيد المساهمة ، ولكن ربما شيء مثل stdtime - ليس كثيرًا.

بالنظر إلى المستقبل ، لا أعتقد أننا يجب أن نستخدم بروتوس الفانيليا بروتوبوف مباشرة في المكونات داخليًا في وقت التشغيل (بالنظر إلى مجموعة الميزات المقدمة من protobuf اليوم).
من المنطقي فقط استخدام protobuf للتسلسل (de-) ، لذلك للتخزين وعلى طبقة 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. إنه شعور مثل دفع العلبة. دعونا نحافظ على الأشياء بأكبر قدر ممكن من الفانيليا ، خاصة عندما نحتاج إلى أن نقرر مرة أخرى أفضل طريقة للمضي قدمًا.

أوافق على أنه يمكننا التفكير في استخدام أنواع وسيطة في بعض الأماكن ، بدلاً من الاعتماد في كل مكان على البروتوس التي تم إنشاؤها. إنه يفصل أساسًا كائنات نقل البيانات (DTOs: protos ، أيضًا للتخزين) عن كائنات الوصول إلى البيانات (DAOs: كيف نستخدمها). إذا كان هذا هو القراءة في المقام الأول ، فيمكننا أيضًا إعلان الواجهات ومعرفة المدى الذي وصلنا إليه في ذلك.

ومع ذلك ، لن أذهب إلى حد تغيير NS بالكامل لاستخدام T_device ، ولكن بالأحرى هياكل و / أو واجهات محددة حسب الحاجة.

دعنا ننتقل هذه المناقشة إلى نوفمبر

rvolosatovs ما هو اعتراضك على الانتقال إلى الفانيليا مع منظم JSON المخصص؟

عبء الترحيل الهائل والأحمال من النموذج المعياري إذا انتهى بنا الأمر فقط باستخدام بروتوس الفانيليا مباشرة.
أنا لا أعترض على ذلك حقًا ، لكني أعتقد أننا يجب أن نحاول إيجاد بديل بسيط غير تدخلي أولاً ، وإذا لم يكن ذلك ممكنًا ، فقم بإعادة صياغة هذا الأمر برمته.

أخشى أن أي مكون إضافي نبدأ في الاعتماد عليه سينتهي به الأمر في حالة غير صيانة في مرحلة ما. بشكل عام ، أنا أؤيد إبقاء الأشياء قريبة من الفانيليا قدر الإمكان. إذا كان هذا يعني أن التحقق من nil أكثر مما نود ، فليكن. يمكن أيضًا أن يكون لصالحنا أننا نعلم أن الأشياء لم يتم ضبطها ، بدلاً من هيكل مُهيأ.

أخشى أن إعادة هيكلة قاعدة الكود الخاصة بنا بالكامل ستكون بمثابة ألم بغض النظر عن كيفية قيامنا بذلك. تُستخدم الهياكل الأولية (التي تم إنشاؤها بواسطة gogo) في كل مكان في الوقت الحالي (واجهة برمجة تطبيقات gRPC ، وواجهة برمجة تطبيقات HTTP ، والأحداث ، والأخطاء ، داخليًا ، و Redis DB ، ...) ، لذا فإن التغيير إلى شيء آخر (أيًا كان هذا الشيء الآخر) سوف يمس إلى حد كبير كل شيء في قاعدة الشفرة لدينا ، والطريقة التي تبدو بها الآن ، كلها في نفس الوقت.

الشرط الصعب هو أننا لا نكسر توافق v3 API الخاص بنا. حتى إذا قررنا استخدام هذا الموقف كلحظة لبدء العمل على v4 API (داخليًا على الأقل) ، فلا يزال يتعين علينا الاستمرار في دعم v3 API للمستخدمين الحاليين.

على المدى الطويل ، أعتقد أننا سنفعل لأنفسنا خدمة كبيرة من خلال فصل واجهات برمجة التطبيقات الخارجية (التي تم إصدارها ، والمستقرة داخل الشركة الرئيسية) من واجهة برمجة التطبيقات (غير المنفردة ، والمستقرة داخل القاصر) الخاصة بنا ووثائق قاعدة البيانات (ذات الإصدار الثابت ، والمستقرة) . يمكننا بعد ذلك كتابة أو إنشاء وظائف للتحويل بين واجهات برمجة التطبيقات الداخلية الخاصة بنا والآخرين.

لكني أعتقد أن هناك بعض الخطوات التي يمكننا اتخاذها الآن:

جسون

من أجل الحفاظ على توافق v3 JSON API الخاص بنا ، أعتقد أن TODO الأول لدينا هو العمل على إنشاء منظمي JSON و unmarshalers الذين يفهمون كيفية تنظيم / إلغاء تنظيم أنواعنا المخصصة. أعتقد أن القيام بذلك أمر ذكي على أي حال لأنه لا يوجد وعد بالاستقرار لتنفيذ Go لتنسيق JSON لمخازن البروتوكول المؤقتة ، لذلك من الأفضل أن نتحكم في ذلك بأنفسنا. يمكن أن يسمح لنا القيام بذلك أيضًا بالنظر في أقنعة المجال عند التنظيم إلى JSON. في وقت التشغيل grpc-gateway يمكننا تسجيل برامج الترميز ، لذا يمكننا فقط كتابة برنامج ترميز يستدعي منظمينا (المُنشأ) (un) بدلاً من {gogo، golang} / protobuf's jsonpb.

إنشاء بروتوس جديدة بجوار القديم

لقد جربت ذلك بالفعل هنا: 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

    • التبديل من protoc-gen-gogottn إلى protoc-gen-gofast (أو أيًا كان ما هو قريب من الفانيليا)

    • أضف خيارات (gogoproto.*) صريح في ملفات proto الخاصة بنا ، بحيث يتم عرضها كما هو الحال الآن

  2. نحتاج إلى إعادة تشكيل الكود الخاص بنا لاستخدام Getters بدلاً من الوصول المباشر إلى الحقل. ربما تساعد أدوات مثل 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 والتأكد من أننا نستخدم Getters حيثما أمكن ذلك ، ونقوم بشيكات صفرية بخلاف ذلك.

    • ...

rvolosatovs دعونا نحاول القيام بهذه الخطوات الأولى للإصدار 3.11.3. عند الانتهاء من ذلك ، يرجى إعادة إضافة المحال إليهم الآخرين ، ودعنا نناقش مرة أخرى.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات