Olahpesan -> PubSub di dalam OTP

OTP adalah singkatan dari Open Telecom Platform ; jadi itu terjadi secara historis, karena platform diciptakan untuk kebutuhan dan uang Ericsson . Tetapi, pada prinsipnya, nama ini memiliki konotasi sebanyak dengan fungsinya seperti apel dengan ponsel berkualitas rata-rata.


Karakteristik pembeda utama OTP, menurut penulis, adalah toleransi kesalahan. Bukan multithreading, bukan model aktor, tidak kaya fitur pencocokan pola, bahkan pengelompokan tidak transparan dan tidak pembaruan kode panas. Toleransi kesalahan.


Mesin virtual Erlang dirancang sangat sederhana: ada banyak "proses" (bukan proses sistem, proses erlang) dengan memori terisolasi yang dapat bertukar pesan. Itu saja. Inilah yang dikatakan Joe Armstrong tentang ini:


Di blog saya, saya berpendapat bahwa proses harus berperilaku seperti orang. Orang-orang memiliki kenangan pribadi dan bertukar data dengan mengirimkan pesan.
- Mengapa saya tidak suka memori bersama

Perpesanan di dalam OTP sangat sederhana: satu proses mengirim pesan ke yang lain (atau sekelompok proses lain), secara sinkron, atau tidak sinkron. Tetapi untuk ini, Anda perlu tahu kepada siapa harus mengirim pesan-pesan ini. Artinya, pengirimnya adalah manajer pertukaran. Tetapi bagaimana jika kita hanya ingin mengirim siaran dan memungkinkan semua proses yang tertarik untuk berlangganan pesan ini?


Ya, ini adalah PubSub biasa, tetapi di luar kotak dalam OTP tidak diterapkan. Yah, itu tidak masalah, kita memiliki semua batu bata dalam satu jam untuk membuatnya bertekuk lutut. Mari kita mulai.


Opsi implementasi


Pada dasarnya, Elixir termasuk modul Registry yang dapat digunakan sebagai perancah untuk pubsub . Sedikit kode tenunan sendiri, penampilan rapi dari semua peserta (pengawas untuk semua orang), dan Anda selesai. Satu-satunya masalah adalah bahwa Registry lokal dan tidak tahu cara mengelompokkan. Artinya, dalam lingkungan terdistribusi (node ​​terdistribusi) keindahan ini tidak akan berfungsi.


Phoenix.PubSub kami, ada implementasi terdistribusi dari Phoenix.PubSub , yang dilengkapi dengan dua implementasi siap pakai: Phoenix.PubSub.PG2 dan Phoenix.PubSub.Redis . Ya, Redis jelas merupakan tautan tambahan dalam rantai kami, tetapi PG2 , yang bekerja di atas kelompok Erlang proses pg2 , adalah itu. Namun, tanpa boilerplate tidak akan berhasil.


Jadi, kami memiliki segalanya untuk membuat langganan PubSub yang nyaman di aplikasi kami. Apakah sudah waktunya membuka editor teks? "Tidak juga." Saya tidak suka menduplikasi kode dari proyek ke proyek, dan semua yang saya dapat mengisolasi ke perpustakaan terisolasi untuk digunakan kembali.


Envío


Jadi paket Envío lahir. Karena obrolan, seperti yang Anda tahu, tidak bernilai sepeser pun, kami akan mulai dengan contoh penggunaan.


Newsletter Lokal → Registry


 defmodule MyApp.Sub do use Envio.Subscriber, channels: [{MyApp.Pub, :main}] def handle_envio(message, state) do # optionally call the default implementation {:noreply, state} = super(message, state) # handle it! IO.inspect({message, state}, label: "Received") # respond with `{:noreply, state}` as by contract {:noreply, state} end end 

Itu, secara umum, itu saja. Tetap MyApp.Sub ke dalam pohon pengawas kami, dan proses ini akan mulai menerima semua pesan yang dikirim menggunakan fungsi dari MyApp.Pub , yang juga tidak dibebani dengan kode.


 defmodule MyApp.Pub do use Envio.Publisher, channel: :main def publish(channel, what), do: broadcast(channel, what) def publish(what), do: broadcast(what) # send to :main end 

Newsletter Terdistribusi → PG2


Untuk sistem terdistribusi yang terdiri dari banyak node, metode ini tidak akan berfungsi. Kami harus dapat berlangganan pesan dari node lain, dan Registry bukan asisten di sini. Tetapi ada PG2 yang mengimplementasikan behaviour sama.


 defmodule Pg2Sucker do use Envio.Subscriber, channels: ["main"], manager: :phoenix_pub_sub def handle_envio(message, state) do {:noreply, state} = super(message, state) IO.inspect({message, state}, label: "Received") {:noreply, state} end end 

Satu-satunya perbedaan dari kode mandiri di atas adalah manager: :phoenix_pub_sub parameter yang kami berikan untuk use Envio.Subscriber (dan use Envio.Publisher ) untuk membangun modul berdasarkan pada :pg2 alih-alih Registry lokal. Sekarang pesan yang dikirim menggunakan Publisher ini akan tersedia di semua node di cluster.


Aplikasi


Envío mendukung apa yang disebut sebagai backends . Envio.Slack hadir dengan Envio.Slack , yang memungkinkan Anda untuk menyederhanakan pengiriman pesan ke Slack . Semua yang diperlukan dari aplikasi adalah mengirim pesan ke saluran yang dikonfigurasi dalam file config/prod.exs - Envío akan melakukan Envío . Berikut ini contoh konfigurasi:


 config :envio, :backends, %{ Envio.Slack => %{ {MyApp.Pub, :slack} => [ hook_url: {:system, "SLACK_ENVIO_HOOK_URL"} ] } } 

Sekarang semua pesan yang dikirim dengan memanggil MyApp.Pub.publish(:slack, %{foo: :bar}) akan dikirimkan ke saluran yang sesuai di Slack , diformat dengan indah. Untuk berhenti mengirim pesan ke Slack , cukup hentikan proses Envio.Slack . Contoh lainnya (misalnya, log in IO ) dapat ditemukan dalam tes.


Mengapa saya menyalibkan, coba sendiri.


 def deps do [ {:envio, "~> 0.8"} ] end 

Komunikasi yang baik!

Source: https://habr.com/ru/post/id481460/


All Articles