bartblast

bartblast

Creator of Hologram

Time to Implement Pub/Sub in Hologram - Looking for Your Input!

With the core component system and HTTP/WebSocket infrastructure solid, it’s time to tackle Pub/Sub support.

What We Have vs What’s Missing

Currently: Actions, Commands, WebSockets and HTTP transport, component communication

Missing: Real-time server-initiated updates

I Want Your Input First

I have ideas about how Pub/Sub should work in Hologram, but I want to hear from you before biasing the discussion.

How would you want to use Pub/Sub?

  • API design and DSL preferences (Phoenix PubSub-like? Something else? etc.)
  • Component/Page integration (how should subscriptions work?)
  • Use cases (chat, notifications, live dashboards, collaboration, etc.)

Thanks for helping shape this!

Most Liked

garrison

garrison

I would strongly favor a declarative sync-based API for tracking server state on the client. I don’t know exactly how this would look (nor do I have a great understanding of Hologram’s existing APIs). But using Phoenix terminology, some way to specify that a given set of assigns should be automatically shipped to the client and kept up to date (with no tearing) would be a good path, I think.

I would not recommend venturing down the path of encouraging developers to maintain synchronization with their own imperative “glue” protocol (i.e. sending their own diffs down the wire by hand). This always ends badly.

kingdomcoder

kingdomcoder

Hi, @bartblast

I think of PubSub in Hologram the same way I think of events—they’re triggers (that sometimes carry data). These server-side “events” can be similarly bound to actions/commands, and the rest of the Hologram plumbing immediately becomes available to us. I imagine new server-side functions put_pubsub and delete_pubsub as the main additions.

Add a Subscription

To subscribe to a PubSub channel, call put_pubsub in init/3 or command/3:

put_pubsub(server, pubsub_channel, command: :my_command)

or

put_pubsub(server, pubsub_channel, action: :my_action)

Delete a Subscription

To unsubscribe from a PubSub channel, call delete_pubsub in command/3:

delete_pubsub(server, pubsub_channel)

or

delete_pubsub(server, pubsub_channel)

I suggest there should also be a cleanup mechanism that unsubscribes when a component is removed from the page.

To Handle a Message

Each time a pubsub message is received, its corresponding command/action is triggered and can be handled as such:

def command(:my_command, pubsub_msg, server) do
  # do something with the message
end
def action(:my_action, pubsub_msg, component) do
  # do something with the message
end

Additionally, I don’t think PubSub handling should be restricted to pages. This is one of the banes I have with LiveView where handle_info is available only in the LiveView and not in LiveComponents. Each component should be able to call put_pubsub and delete_pubsub in its own init/3 and command/3 functions.

Finally, I wouldn’t recommend adding a target option to put_pubsub where a subscription in one page/component can trigger a command or action in another. Each page/component should subscribe independently to a channel if it needs to react to messages. This is not a “hard” suggestion, but I think it will help avoid confusion.

PS: Thank you for always welcoming input from the community. We’re grateful for your hard work :clap: :clap:

bartblast

bartblast

Creator of Hologram

Hi @jonas_h, thanks for the kind words and the nudge!

Short version: I’m no longer planning a dedicated PubSub API. The plan is now Local-First sync for data, plus Server-triggered actions for ephemeral events (notifications, presence, typing indicators, etc.).

Reasoning is in this reply from a few months back - short of it: PubSub for data sync forces you to wire up reconciliation by hand, which is exactly what leads to the bugs people keep running into. A declarative local-first layer handles that automatically. I also covered this in my recent ElixirConf talk - I’ll share the recording when it’s up.

Where things stand:

  • Server-triggered actions are in progress and will ship in v0.9.0. Low-level primitive for ephemeral events, similar in spirit to PubSub - covers most realtime use cases.
  • Local-First sync is still in the design phase (discussion here). The end goal is a declarative auto-sync store, so most apps won’t need the low-level primitive at all.

What you can do today: the linked reply also covers workarounds - polling-command + Hologram.JS.exec/1, Phoenix Channels alongside Hologram, etc. @ken-kost’s skribbl.io integration is likely along those lines - looking forward to his write-up.

Thanks for your patience, and glad you’re enjoying Hologram!

Where Next?

Popular in Discussions Top

sashaafm
I’m trying to evaluate the best combo/stack for a BEAM Web app. Right now I’m exploring Yaws a bit, after having dealt with Phoenix for a...
New
Fl4m3Ph03n1x
Background This question comes mainly from my ignorance. Today is Black Friday, one of my favorite days of the year to buy books. One boo...
New
mmmrrr
Just saw that dhh announced https://hotwire.dev/ Is it just me or is this essentially live view? :smiley: Although I like the “iFrame-e...
New
fireproofsocks
I’ve been working on an Elixir project that has required a lot of scripting. I usually reach for Elixir because I like it more (and in th...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
rms.mrcs
A couple of days ago I was discussing with a friend about different approaches to write microservices. He said that if he was going to w...
New
chulkilee
Here are the list of HTTP client libraries/wrappers, and some thoughts on HTTP client in general. I’d like to hear from others how they w...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
fireproofsocks
This is more of a general question, but I’m wondering how other people in the community think about the pattern matching in function sign...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement