Lorawan-stack: Selidiki masa depan plugin gogo proto

Dibuat pada 25 Jun 2020  ·  15Komentar  ·  Sumber: TheThingsNetwork/lorawan-stack

Ringkasan

https://github.com/gogo/protobuf tidak dikelola lagi https://github.com/gogo/protobuf/issues/691 (saat ini)

Kenapa kita perlu ini?

Ini ketergantungan kami, yang tidak kompatibel dengan versi golang/protobuf baru, yang semakin banyak bergantung pada paket, maka kami perlu mengganti versi golang/protobuf , tergantung pada versi lama dari dependensi langsung kami dan bahkan berpotensi memecahkan paket dengan cara ini

Apa yang sudah ada? Apa yang kamu lihat sekarang?

gogo/protobuf ketergantungan

Apa yang hilang? Apa yang ingin kau lihat?

Cari tahu ini

Bagaimana Anda mengusulkan untuk menerapkan ini?

Cari tahu apakah pengelola baru akan muncul atau plugin yang berbeda dengan paritas fitur?
Pakai vanilla protobuf saja?

Bagaimana Anda mengusulkan untuk menguji ini?

tes

Bisakah Anda melakukannya sendiri dan mengajukan Permintaan Tarik?

Ya

dependencies technical debt

Komentar yang paling membantu

Silakan rencanakan panggilan untuk minggu depan sehingga kita bisa berdiskusi secara offline.

Saya pikir kita harus melalui proses rasa sakit ini dan berkonsentrasi untuk menyelesaikannya dalam satu atau dua minggu. Dan untuk menghindarinya kami melakukan hal-hal lain karena ini akan menyebabkan banyak konflik. Memiliki tangan sebanyak mungkin membutuhkan mengetahui persis apa yang akan kita lakukan dalam kasus apa, membagi tugas sebanyak mungkin dan mengawasi hadiah.

Semua 15 komentar

Plugin validasi yang kami gunakan untuk menjatuhkan dukungan untuk GoGo
https://github.com/envoyproxy/protoc-gen-validate/pull/340

Saya pikir cara terbaik ke depan adalah mengikuti ekosistem dan bermigrasi dari gogo/protobuf. Dengan semakin banyak dependensi kami yang lain menjauh dari gogo, saya pikir akan semakin sulit untuk terus menggunakannya. Tentu saja akan banyak pekerjaan untuk bermigrasi, jadi jika kita melakukannya, kita perlu membuat rencana yang baik.

@rvolosatovs mungkin tahu lebih banyak tentang opsi khusus yang diatur di generator gogottn , tetapi inilah yang saya temukan untuk opsi eksplisit dalam file proto kami:

  • Kita bisa mulai dengan menghapus opsi gogoproto.customname , gogoproto.stdtime dan gogoproto.stdduration , dan goproto_enum_prefix . Itu relatif mudah untuk dihapus, karena kompiler Go akan segera mengeluh tentang masalah yang dihasilkan.
  • Menghapus opsi gogoproto.embed berarti bahwa kita tidak dapat lagi mengakses bidang yang disematkan (kompiler Go akan membantu kita menemukannya), dan bahwa pesan tidak lagi memenuhi beberapa antarmuka (ini mungkin lebih sulit).
  • Opsi gogoproto.nullable akan lebih berhasil, karena kita harus mulai menggunakan getter, dan menambahkan nil-checks. Masalah yang dihasilkan mungkin tidak tertangkap oleh compiler Go. Solusi yang mungkin adalah membuat bidang tersebut menjadi pribadi untuk sementara, kemudian menulis ulang ke getter/setter dan akhirnya menjadikan bidang tersebut publik lagi.
  • Apa yang akan cukup bermasalah adalah bidang yang menggunakan gogoproto.customtype dan enum yang menggunakan opsi gogoproto.enum_stringer . Bagi mereka, kami sering mengubah cara mereka menyusun/tidak mengatur ke JSON. Untuk bidang bytes seperti EUI, DevAddr, dll., kita dapat mengubah jenisnya (dalam pesan proto) menjadi string (yang kompatibel dengan biner). Dengan enum, saya khawatir itu akan merusak JSON API, karena itu sekarang diterima (oleh UnmarshalJSON) sebagai string dan int.

Mungkin ini juga saat yang tepat untuk mulai memikirkan API v4 kami, karena saya bisa membayangkan kami mungkin menemukan beberapa kejutan lagi (pemecahan API).

Saya pikir cara terbaik untuk maju adalah mencoba terlebih dahulu https://github.com/alta/protopatch. Tergantung pada hasilnya:

  • Jika semua kebutuhan kita terpenuhi -> migrasi dan lupakan ini (seharusnya hanya cari-dan-ganti di direktori api )
  • Jika hanya sebagian dari kebutuhan kita yang tercakup dan ada opsi khusus yang tidak tercakup oleh plugin -> kita harus mengevaluasi per opsi dan menghapus opsi khusus ini atau, mungkin, berkontribusi pada protopatch jika itu fitur upaya rendah. Ini benar-benar tergantung pada opsi, meskipun - jika kita berbicara tentang customtype - bahwa IMO pasti membenarkan kontribusi, tetapi mungkin sesuatu seperti stdtime - tidak terlalu banyak.

Ke depan, saya tidak berpikir kita harus langsung menggunakan protobuf vanilla dalam komponen secara internal saat runtime (mengingat set fitur protobuf yang disediakan hari ini).
Masuk akal untuk menggunakan protobuf untuk (de-)serialisasi, jadi untuk penyimpanan dan pada lapisan API. Secara internal, bagaimanapun, menggunakan protos Go yang dihasilkan vanila biasa tidak masuk akal bagi saya.
Jadi, misalnya, NS:

  1. dapatkan *ttnpb.EndDevice (tipe Go yang dihasilkan vanila) dari registri, deserialized dari data biner yang tersimpan
  2. convert *ttnpb.EndDevice menjadi T_device , (CATATAN: mungkin itu hanya pembungkus awalnya atau selamanya)
  3. gunakan T_device internal di NS
  4. convert T_device menjadi *ttnpb.EndDevice (CATATAN: ini bisa menjadi tugas yang sepele dan sangat cepat jika kita menggunakan pembungkus, karena kita hanya perlu memodifikasi bidang yang diubah dan itu bahkan dapat dilakukan pada biner data secara langsung)
  5. set *ttnpb.EndDevice , bersambung menjadi data biner

Referensi juga https://github.com/TheThingsNetwork/lorawan-stack/issues/342 (populator yang dihasilkan)

Saya tidak mendukung alternatif (lebih kecil) untuk gogo. Rasanya seperti mendorong kaleng. Mari kita menjaga hal-hal sebagai vanila mungkin, terutama ketika kita perlu memutuskan lagi apa jalan terbaik ke depan.

Saya setuju bahwa kita dapat mempertimbangkan untuk menggunakan jenis perantara di beberapa tempat, daripada mengandalkan di mana-mana pada proto yang dihasilkan. Ini pada dasarnya memisahkan objek transfer data (DTO: protos, juga untuk penyimpanan) dari objek akses data (DAO: bagaimana kami menggunakannya). Jika itu terutama membaca, kami juga dapat mendeklarasikan antarmuka dan melihat seberapa jauh kami melakukannya.

Yang mengatakan, saya tidak akan pergi sejauh mengubah seluruh NS menggunakan T_device , melainkan struct dan/atau antarmuka yang spesifik sesuai kebutuhan.

Mari kita pindahkan diskusi ini ke November

@rvolosatovs apa keberatan Anda untuk pindah ke vanilla dengan marshaler JSON khusus?

Beban migrasi yang besar dan beban boilerplate jika kita akhirnya hanya menggunakan vanilla protos secara langsung.
Saya tidak benar-benar keberatan dengan itu, saya hanya berpikir kita harus mencoba mencari alternatif non-intrusif sederhana terlebih dahulu dan jika itu tidak memungkinkan, maka gunakan untuk mengerjakan ulang semua ini.

Saya khawatir plugin apa pun yang mulai kita andalkan akan berakhir dalam keadaan tidak terawat di beberapa titik. Secara umum, saya mendukung menjaga hal-hal sedekat mungkin dengan vanilla. Jika itu berarti nil memeriksa lebih sering daripada yang kita suka, maka biarlah. Itu juga dapat menguntungkan kita karena kita tahu bahwa segala sesuatunya tidak disetel, alih-alih struct yang diinisialisasi.

Saya khawatir refactoring seluruh basis kode kita akan merepotkan tidak peduli bagaimana kita melakukannya. Proto struct kami (dihasilkan gogo) digunakan di mana-mana saat ini (gRPC API, HTTP API, event, error, internal, Redis DB, ...), jadi mengubah ke sesuatu yang lain (apa pun itu) akan menyentuh hampir semua hal dalam basis kode kami, dan tampilannya sekarang, semuanya pada waktu yang sama.

Persyaratan sulitnya adalah kami tidak merusak kompatibilitas API v3 kami. Bahkan jika kami memutuskan untuk menggunakan situasi ini sebagai momen untuk mulai mengerjakan API v4 (setidaknya secara internal), kami masih harus tetap mendukung API v3 itu untuk pengguna yang sudah ada.

Dalam jangka panjang, saya pikir kita akan sangat membantu diri kita sendiri dengan memisahkan API eksternal (berversi, stabil-dalam-utama) kami dari API internal (tidak berversi, stabil-dalam-minor) dan dokumen database (berversi, stabil) kami . Kami kemudian dapat menulis atau menghasilkan fungsi untuk mengonversi antara API internal kami dan lainnya.

Tapi menurut saya ada beberapa langkah yang sudah bisa kita ambil sekarang:

JSON

Untuk menjaga agar v3 JSON API kami kompatibel, saya pikir TODO pertama kami adalah bekerja untuk menghasilkan marshaler dan unmarshaler JSON yang memahami cara menyusun/menghapus jenis kustom kami. Saya pikir melakukan ini cerdas karena tidak ada janji stabilitas untuk implementasi Go dari format JSON untuk buffering protokol , jadi kami lebih baik memiliki kendali atas itu sendiri. Melakukan hal ini juga memungkinkan kita untuk mempertimbangkan field mask saat menyusun ke JSON. Dalam runtime grpc-gateway kita dapat mendaftarkan codec, jadi kita cukup menulis codec yang memanggil marshaler kita sendiri (yang dihasilkan) (un) alih-alih jsonpb {gogo,golang}/protobuf.

Hasilkan proto baru _di samping_ yang lama

Saya sudah mencobanya di sini: https://github.com/TheThingsNetwork/lorawan-stack/commit/a41f62d98ae7ee719b576e6fcd2009a79cd38f4c

Hal ini membuat protobuf mengeluh tentang jenis registri, jadi kami mungkin perlu menghapus golang_proto.RegisterType dari proto lama kami agar ini berfungsi. Menghapus yang berpotensi merusak penyelesaian google.protobuf.Any , tetapi kami hanya menggunakannya dalam kesalahan dan peristiwa, jadi kami mungkin dapat menemukan solusi untuk kasus tertentu tersebut.

Hasilkan fungsi untuk mengonversi antara proto lama dan baru

Ini hanya untuk masa transisi, tetapi untuk solusi jangka panjang, kami ingin membuat konverter serupa.

Perbarui layanan satu per satu

Saya sudah mencobanya dengan layanan sederhana di sini: https://github.com/TheThingsNetwork/lorawan-stack/commit/cd7d75c8b42ad15eee1ac594ff6d0f2d5a75eb67 , tetapi untuk layanan yang lebih rumit kami pasti membutuhkan konverter itu.

Perhatikan bahwa ini hanya mengubah layanan grpc itu sendiri. Gerbang grpc masih menggunakan hal-hal gogo lama di sisi JSON, dan kemudian memanggil server gRPC internal, yang kemudian menjalankan implementasi baru.

Mendorong beberapa pembaruan ketergantungan awal dan solusi kompatibilitas mundur di sini: https://github.com/TheThingsNetwork/lorawan-stack/compare/issue/2798-codec

Semakin banyak dependensi kami yang ditingkatkan ke protobuf 1.4 dan V2 API, dan semakin lama kami membukanya, semakin banyak masalah yang akan kami hadapi saat mencoba meningkatkan dependensi kami.

Kita harus benar-benar memberikan ini lebih banyak prioritas dan membuat keputusan tentang apa yang akan kita lakukan tentang semua ini.

Silakan rencanakan panggilan untuk minggu depan sehingga kita bisa berdiskusi secara offline.

Saya pikir kita harus melalui proses rasa sakit ini dan berkonsentrasi untuk menyelesaikannya dalam satu atau dua minggu. Dan untuk menghindarinya kami melakukan hal-hal lain karena ini akan menyebabkan banyak konflik. Memiliki tangan sebanyak mungkin membutuhkan mengetahui persis apa yang akan kita lakukan dalam kasus apa, membagi tugas sebanyak mungkin dan mengawasi hadiah.

Langkah selanjutnya:

  1. @rvolosatovs memperbarui perkakas agar sedekat mungkin dengan "vanila":

    • Hapus hal-hal seperti unconvert , gofumpt dan apa pun yang kami lakukan di atas protoc

    • Beralih dari protoc-gen-gogottn ke protoc-gen-gofast (atau apa pun yang paling dekat dengan vanilla)

    • Tambahkan opsi (gogoproto.*) eksplisit di file proto kami, sehingga mereka membuat sama seperti sekarang

  2. Kami perlu memfaktorkan ulang kode kami untuk menggunakan Getter alih-alih akses lapangan langsung. Mungkin alat seperti gopls dan rf dapat membantu dalam hal ini.
  3. Kami mulai menghapus opsi (gogoproto.*) satu per satu dan memperbarui kode yang menggunakannya. Mungkin alat seperti gopls dan rf dapat membantu dalam hal ini.

    • Menghapus gogoproto.populate dan memperbarui tes (https://github.com/TheThingsNetwork/lorawan-stack/issues/342)

    • Menghapus gogoproto.customname dan mengubah EUI -> Eui dll.

    • Menghapus gogoproto.embed . Kita perlu memastikan bahwa pesan masih mengimplementasikan antarmuka seperti ValidateContext(context.Context) error dan ExtractRequestFields(m map[string]interface{}) .

    • Menghapus gogoproto.nullable dan memastikan kami menggunakan Getter jika memungkinkan, dan melakukan pemeriksaan nil sebaliknya.

    • ...

@rvolosatovs mari kita coba membuat langkah pertama untuk v3.11.3. Setelah selesai, tambahkan kembali penerima tugas lainnya, dan mari kita diskusikan lagi.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat