Migrasi yang berhasil ke solusi XMPP khusus
Diterbitkan: 2019-04-08Saya akan memberi tahu Anda tentang tantangan yang kami hadapi saat bermigrasi dari obrolan pihak ketiga ke solusi perpesanan berbasis XMPP khusus untuk klien kami, Forward Health, solusi perawatan kesehatan perpesanan yang berbasis di Inggris. Artikel ini akan membahas alasan migrasi, harapan kami versus kenyataan implementasi, dan tantangan membangun fungsionalitas tambahan.
Di mana kita mulai
Forward Health, klien kami, ingin membangun aplikasi komunikasi seluler untuk petugas kesehatan di Inggris, termasuk fungsi obrolan. Sebagai startup, mereka ingin menunjukkan produk kerja mereka dengan cepat. Pada saat yang sama, pesan harus dapat diandalkan, kuat, dan mampu mengirim data pasien yang sensitif dengan aman. Untuk mencapai ini, kami memutuskan untuk menggunakan salah satu solusi pihak ketiga yang tersedia untuk fungsionalitas obrolan .
Fungsi chat bukanlah hal yang sepele, apalagi jika ditujukan untuk mendukung industri kesehatan. Saat aplikasi berkembang, kami menemukan lebih banyak kasus tepi dan beberapa bug di sisi perpustakaan yang tidak mau dikerjakan oleh pihak ketiga. Selain itu, Forward Health ingin menambahkan fitur baru yang tidak didukung oleh perpustakaan pihak ketiga. Beralih ke solusi khusus adalah langkah berikutnya.
Saat itulah kami mulai bekerja dengan MongooseIM . MIM adalah solusi open source berdasarkan protokol XMPP yang sudah mapan. Kami bekerja dengan perusahaan eksternal Erlang Solutions Limited untuk menyiapkan backend kami dan memberikan dukungan dengan menerapkan solusi khusus.
Pada awalnya, segala sesuatu tentang pengiriman pesan tampak berbeda. Sebelumnya, semua kebutuhan kami dipenuhi oleh SDK dan REST API-nya. Sekarang, dengan menggunakan MongooseIM, kami harus meluangkan waktu untuk memahami sifat XMPP dan mengimplementasikan SDK kami sendiri . Ternyata server XMPP "telanjang tulang" hanya mengirimkan bait (pesan XML) antar klien secara real-time. Stanza bisa dari berbagai jenis, yaitu pesan obrolan biasa, kehadiran, permintaan, dan tanggapan. Berbagai macam modul dapat ditambahkan ke server, misalnya, menyimpan pesan, dan membiarkan klien menanyakannya.
Di sisi klien (Android, iOS) ada beberapa SDK tingkat rendah. Sayangnya, mereka hanya bertindak sebagai lapisan yang memungkinkan komunikasi dengan MongooseIM dan beberapa modul pluggable-nya yang disebut XEP (Protokol Ekstensi XMPP bertanggung jawab, antara lain, untuk mengirim pemberitahuan push untuk setiap pesan). Seluruh arsitektur untuk penanganan pesan, penyimpanan dan permintaan pesan, harus diimplementasikan oleh tim kami.
Apa yang menyelamatkan kami adalah perpustakaan pihak ketiga yang telah kami gunakan sebelumnya. Itu memiliki API yang dipikirkan dengan matang, jadi kami membuat solusi kami bekerja dengan cara yang sama. Kami memisahkan kode khusus XMPP ke dalam SDK internal kami dengan antarmuka yang sesuai dengan salah satu dari solusi sebelumnya. Ini hanya menghasilkan beberapa perubahan dalam kode aplikasi kami setelah migrasi.
Selama implementasi MongooseIM, kami dikejutkan beberapa kali oleh elemen yang kami pikir akan menjadi standar, tetapi tidak tersedia untuk kami, bahkan oleh XEP.
Menerapkan fitur utama obrolan berbasis XMPP
Stempel waktu
Anda mungkin berpikir, seperti yang kami lakukan, bahwa stempel waktu akan sesederhana "Saya mendapatkan pesan, saya menampilkan ini di UI dengan stempel waktu." Tidak, tidak semudah itu. Secara default, bait pesan tidak memiliki bidang stempel waktu. Untungnya bagi tim kami, XMPP adalah protokol yang mudah dikembangkan. Di bagian belakang, kami menerapkan fitur khusus, menambahkan stempel waktu ke setiap pesan yang melewati server MongooseIM. Kemudian penerima akan memiliki stempel waktu yang dilampirkan pada pesan.
Mengapa pengirim tidak dapat menambahkan stempel waktu sendiri? Yah, kami tidak tahu apakah mereka mengatur waktu yang tepat di ponsel mereka.
Mengapa tidak ada XEP untuk itu? Mungkin karena XMPP merupakan protokol real-time, maka secara teoritis setiap pesan yang dikirim langsung diterima.
EDIT: Seperti yang ditunjukkan Florian Schmaus: "Sebenarnya ada satu, meskipun dapat dengan mudah dilewatkan karena namanya yang membingungkan: XEP-0203: Pengiriman Tertunda." Itu menambahkan stempel waktu ke pesan hanya jika pengirimannya tertunda. Jika tidak, pesan baru saja dikirim.
Pesan Offline
Ketika kedua pengguna masuk ke aplikasi, mereka dapat mengirim pesan satu sama lain secara real-time. Namun bagaimana jika salah satunya sedang offline? Jawaban cepatnya adalah: pesan harus disangga di backend . Fitur pesan offline menangani pekerjaan ini dan mengirimkan semua bait yang disangga ke pengguna setelah mereka masuk kembali.
Tapi kemudian muncul beberapa pertanyaan:
- Berapa lama pesan-pesan ini harus disangga?
- Berapa banyak dari mereka?
- Haruskah mereka dikirim ulang setelah masuk kembali? Tapi itu akan membanjiri klien dengan pesan, bukan?
- Bagaimana jika pengguna hanya masuk, tetapi tidak masuk ke obrolan dengan pesan baru. Apakah mereka semua akan pergi?
- Bagaimana jika pengguna masuk di beberapa perangkat?
Menjadi jelas bahwa fitur Pesan Offline hanya dapat mengirim pesan ke perangkat pertama yang kembali online, dan pesan-pesan itu kemudian akan hilang untuk semua perangkat lain. Kami memutuskan untuk membuang fitur ini, dan menyimpan pesan di backend XMPP dengan cara yang berbeda dan persisten.

Manajemen Arsip Pesan (MAM)
MAM adalah penyimpanan di server untuk pesan. Ketika klien masuk, mereka dapat meminta server untuk pesan. Anda dapat melakukan kueri berdasarkan halaman, Anda dapat melakukan kueri berdasarkan tanggal. Ini fleksibel — Anda bahkan dapat menanyakan halaman sebelum atau sesudah pesan dengan ID tertentu, menambahkan filter untuk pesan dari percakapan yang tepat.
Tapi di sini adalah menangkap. Pesan obrolan normal disimpan terbungkus dalam pesan MAM, yang memiliki ID uniknya sendiri. Saat pengguna menerima pesan chat di streaming, pesan tersebut tidak berisi ID MAM. Mereka harus meminta MAM untuk mendapatkannya.
Mengambil dari MAM adalah permintaan jaringan, yang berarti dapat memakan waktu yang relatif lama. Saat pengguna memasuki obrolan, mereka ingin segera melihat pesan. Jadi kita juga membutuhkan database lokal .
Ketika pengguna mendapatkan pesan dalam aliran (pesan online), kami menyimpannya ke database lokal dan menunjukkannya kepada pengguna. Dengan begitu, kami menampilkan pesan yang tiba secara real-time dengan cepat kepada pengguna.
Selain itu, setiap kali mereka memasuki layar obrolan, kami mengunduh semua pesan dari sekarang ke pesan MAM terbaru yang disimpan di DB lokal untuk percakapan itu dan memasukkannya ke dalam database, mengabaikan duplikat.
Inilah cara kami menangani penyimpanan pesan lama. Juga, kami yakin bahwa dalam database ada satu set lengkap pesan untuk percakapan tertentu antara pesan pertama dan terakhir dari MAM.
Untuk melacak pesan yang diunduh dari MAM, kami telah menambahkan dua properti ke entitas percakapan:
- Id MAM dari pesan MAM terbaru di database
- Id MAM dari pesan MAM tertua di database
Menangani kumpulan pesan MAM yang hancur dalam database lokal akan sangat bermasalah.
Selain itu, memiliki dua properti ini untuk setiap percakapan memungkinkan kita untuk menyimpan pesan obrolan normal di database sambil mengabaikan pembungkus — pesan MAM. Dan ketika pengguna memasuki obrolan, kami dapat menampilkan pesan terbaru dari database dan mengambil pesan yang hilang dari MAM di latar belakang.
kotak masuk
Setiap aplikasi berbasis obrolan memerlukan layar dengan daftar obrolan—tempat Anda dapat melihat nama, pesan terakhir, dan jumlah pesan yang belum dibaca. Harus ada solusi untuk itu!
Sebenarnya, tidak ada… Ada sesuatu yang disebut Daftar Nama — itu dapat menampung daftar pengguna yang ditandai sebagai “teman.” Sayangnya, tidak ada pesan terakhir, atau jumlah pesan yang belum dibaca yang menyertainya. Tentu, Anda bisa mendapatkan informasi yang dibutuhkan dari backend secara berkeping-keping. Awalnya, kami ingin melakukannya seperti itu, tetapi itu akan berjalan lambat dan rumit untuk dilakukan. Saat itulah kami mulai bekerja dengan Erlang Solutions pada fitur Inbox, yang juga sedang menuju open source.
Saat pengguna terhubung ke backend XMPP, aplikasi mengambil kotak masuk mereka, yang berisi semua percakapan pengguna tersebut — baik obrolan satu lawan satu maupun obrolan tim. Masing-masing memiliki pesan terakhir yang dilampirkan dan jumlah pesan yang belum dibaca. Aplikasi menyimpan seluruh kotak masuk ke database lokal. Saat pengguna berada di aplikasi, dan pesan baru tiba, kami memperbarui status kotak masuk secara lokal. Dengan begitu, aplikasi tidak perlu mengambil kotak masuk untuk setiap pesan baru.
Ringkasan
Beberapa solusi obrolan pihak ketiga menyediakan abstraksi tingkat tinggi. Tidak apa-apa jika Anda ingin membuat aplikasi obrolan sederhana. Dengan menerapkan solusi berbasis XMPP kami sendiri di aplikasi Teruskan, kami dapat memperoleh akses tingkat rendah yang jauh lebih baik, yang membuat pemecahan masalah menjadi lebih mudah. Tentu, butuh beberapa waktu, tetapi sekarang kami tahu bahwa kami dapat menyediakan fitur khusus apa pun untuk membantu dokter di Inggris berkomunikasi dengan cara yang aman dan mudah yang disetujui oleh NHS.
Pesan adalah semua tentang kinerja tinggi, komunikasi real-time. Dengan beralih ke MIM, kami dapat mengoptimalkan setiap bagian dari solusi untuk meningkatkan kecepatan, keandalan, dan pada akhirnya kepercayaan. Saat ini, kami memiliki seluruh kode, jadi mudah untuk melacaknya. Selain itu, kami sedang menjalani fase stabilisasi dan sejumlah laporan yang terkait dengan pengiriman pesan telah menurun secara drastis. Pengguna senang bisa mempercayai platform.
Merancang dan menulis SDK kami sendiri adalah tugas yang menantang dan kami menyukainya. Itu adalah sesuatu yang berbeda dari aplikasi sederhana di mana Anda perlu mengambil data dari server dan menampilkannya di layar. Selama implementasi, kami memahami banyak pilihan desain API perpustakaan pihak ketiga yang kami gunakan sebelumnya. Mengapa? Karena kita pernah mengalami masalah yang sama.