When to use {:noreply, socket} vs {:reply, :ok, socket} in a Phoenix Channel? - phoenix-framework

I'm building a Javascript client app that has live communication with a Phoenix server, and wants to know if a message pushed to the server has been received. It looks like Phoenix's socket.js wants me to use something like:
channel.push("mymessage", {data: 123})
.receive("ok", function(){ console.log("Message pushed successfully"); });
However, I can't get this event handler to fire unless I change my return value on the Phoenix app to be {:reply, :ok, socket}, like so:
def handle_in("mymessage", %{"data" => data} = payload, socket) do
{:reply, :ok, socket}
# not {:noreply, socket}
end
I guess it makes sense that {:noreply, socket} doesn't actually send a message in response to the client, but in what case would you want to send a message to the server and not have it let you know that it worked? Or am I misunderstanding something? I feel like with normal HTTP requests, you always check if the request was successful from the client.

You're right: {:reply, :ok, socket} will send a reply message with "ok", and {:noreply, socket} won't send anything in response. You should use the former if you want to ensure that the message was sent, but often that's impractical or unnecessary (think of broadcasting a chat message to thousands of connected users--it's impractical to track "ack" messages for all of them).
I feel like with normal HTTP requests, you always check if the request was successful from the client.
WebSockets exist for situations that normal HTTP requests don't work well, and one-way communication is one of those cases.

Related

How to see/track the exact HTTP response (code and message) that an Eventgrid webhook endpoint receives?

I have a Webhook Eventgrid subscription. I do not have access to the webhook logs or implementation.
Apparently ,Eventgrid receives HTTP code other than success from the webhook, but I do not have any detail visibility to that.
How can I see the exact HTTP interaction (Response message, HTTP Code) for the EventGrid WebHook Bad Requests like the ones pointed below?
You need to configure the dead letter on your event grid subscription as documented here.
Once the events are not delivered and dead letter now you can review the lastDeliveryOutcome property on the dead letter events to know what was the reason the event was not delivered to the configured endpoint.
You cannot find the reason for each request at your end as the event may be delivered at a later point in time once it is retried.

Are Server-Sent Events sending headers each time an event is sent from the server or just when the connection is created?

I have to make a choice between WebSockets and SSE for an app that should send events in order to update a newsfeed on my website.
I kind of want to use SSE for this task since i don't have to allow users to send events to the server, i just want them to receive events.
Question is: are SSEs sending headers each time an event is sent from the server or just when the connection is created and the sends just the content of an event? If SSE send headers with each event should i use WebSockets to reduce bandwidth?
With SSE, headers are sent only when the connection is created. After that you simply send event data to each open connection as needed.
For one-way traffic, SSE generally uses less server resources than WebSockets and runs over normal http/https protocol for lower risk of firewall/gateway issues. Even group chat can be implemented with a combination of SSE and AJAX.
Some example Node.js code:
const connections = [];
function connect(req, res) {
connections.push(res);
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no'
});
req.on('close', () => {
connections.splice(connections.indexOf(res), 1);
});
}
function send(data) {
connections.forEach(c => c.write(`data:${JSON.stringify(data)}\n\n`));
}
Server-Sent Events official specs:
https://html.spec.whatwg.org/multipage/server-sent-events.html
https://www.w3.org/TR/eventsource/
Marmelab has one was the most useful tutorials because it shows how to configure routes for multiple chat rooms:
https://marmelab.com/blog/2020/10/02/build-a-chat-application-using-sveltejs-and-sse.html
Here's a superb demonstration of how response objects can be stored in array with no other identifiers
and deleted when the connection is closed. Wow! How the heck does Node.js compare responses? #hashcodes?
https://cri.dev/posts/2021-05-11-simple-server-sent-events-sse-eventsource-nodejs-javascript
One of many good tutorials from DigitalOcean community:
https://www.digitalocean.com/community/tutorials/nodejs-server-sent-events-build-realtime-app
A very popular reference with a note re: Cross-document messaging security via EventSource.origin:
https://www.html5rocks.com/en/tutorials/eventsource/basics/
Watch out for compression middleware:
https://jasonbutz.info/2018/08/server-sent-events-with-node

Detect when client closes a connection from aiohttp request handler

I have a long running request during which I push data down to a client as it is received. However, the request requires some resources that are created server side that I'd like to clean up whenever the client disconnects. I've looked through the docs, but I can't seem to find a way to detect when that happens. Any ideas?
This isn't super obvious looking at the docs, but the key here is that the asyncio server will throw a CancelledError into handler coroutine when the connection is closed. You can catch the CancelledError wherever you wait for an asynchronous operation to complete.
Using this, I clean up after a connection with something like this:
async def passthrough_data_until_disconnect():
await create_resources()
while True:
try:
await get_next_data_item()
except (concurrent.futures.CancelledError,
aiohttp.ClientDisconnectedError):
# The request has been cancelled, due to a disconnect
await do_cleanup()
# Re-raise the cancellation error so the handler
# task gets cancelled for real
raise
else:
await write_data_to_client_response()

Persistent Connection with OnReceived response

I'm just starting to learn about "Persistant Connections" in SignalR and like for instance that I'm able to send out pre-serialized json.
But this method of sending from the client, receiving serverside and then send back any respons again is a bit counterintuitive to work with.
Is there any way if doing some simple basic piepelineing on top of "Persistant Connections" without resorting back to Hubs?
I just want to be able to do something like this:
connection.send({ 'command': 123 }).then(function (confirmation) {
if (!confirmation.ok) alert('Command failed');
});
Also, if an exception is thrown in the servers OnReceived, where does it go? Is it swallowed by SignalR? Do I have to catch and send back some kind of error-object myself?

How to get bounce emails from SparkPost without using webhooks?

We are working at the integration of our email application with SparkPost. The only issue we have is getting bounce emails from SparkPost to exclude them from future mailings. Our application retrieves bounce emails directly from the mail server. When the user uses the SparkPost SMTP settings in our software, he cannot retrieve and process bounce emails because SparkPost does not forward bounce messages to the user's bounce email address.
Webhooks will not work for us because they pull data in real time only. If our software is turned to off when the bounce email comes, the bounce will not be caught and will be lost for our software as there is no way to retrieve it at a later time.
So, please, let me know if there is a way to get bounce emails from SparkPost through API or via email just like Amazon SES does. Amazon SES simply forwards bounce emails to the email address specified by the user in our application (Return email header field in the message header).
If you cannot accept pushed data via HTTP like event webhooks or even our relay webhooks, the next best thing would be our Message Events API(https://www.sparkpost.com/api#/reference/message-events/message-events/search-for-message-events)
You could make a request to just get bounces for last hour like this:
https://api.sparkpost.com/api/v1/message-events?events=bounce,out_of_band
If you want more specific time ranges just add a from/to as well as a timezone if you need that:
https://api.sparkpost.com/api/v1/message-events?from=2015-09-10T00:00&to=2015-09-10T23:59&timezone=America/New_York
I wrote the following ruby code to get them as CSV:
require 'net/http'
require 'json'
require 'csv'
uri = URI('https://api.sparkpost.com/api/v1/message-events?events=bounce,out_of_band')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = 'application/json'
req['Authorization'] = ENV['API_KEY'] || raise('please provide API_KEY env variable')
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |https|
https.request(req)
end
bounces = JSON.parse(res.body)['results']
puts "#{bounces.count} bounces found"
CSV.open("bounces.csv", "wb") do |csv|
csv << %w(Timestamp Recipient Reason)
bounces.each do |bounce|
csv << [bounce['timestamp'], bounce['rcpt_to'], bounce['reason']]
end
end
Available as gist here: https://gist.github.com/schmijos/05d2f989c7a5854fe2cd31c666f61c39

Resources