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
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)
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!