instant updates from route handler to frontend
So I have a webhook server that lets me know when a PayPal invoice has been paid.
And I have a dynamic route (/transaction/{id})
I want to immediately change my frontend when this invoice gets paid on the correlating id.
Rn I have a use state that checks for transaction status changes in mongodb.
So since the webhook runs on a route handler, I’m able to update the transaction’s state in mongodb, but Im not able to let the frontend use effect know that it’s been updating.
I don’t really want to poll as I want this flow to be as instant as possible, the user pays invoice in PayPal, frontend changes.
How could I do this?
24 Replies
Websockets, long polling, and server sent events would all solve this issue, and would feel nearly instant to the user. 🙂
alr but wouldnt polling have the longest delay?
also what would be the easiest to setup? websockets or server sent events? and are there docs or examples of this in nextjs?
Long polling doesn't really have a long delay as long as there aren't many messages in rapid succession.
The way long polling works is that the client sends a request to the server over http. Then the server holds the request without responding until it needs to send something. Every so often this is redone to not reach any time-out limits, but it's quite instant for all intents and purposes
If your app, in general, needs a lot of interactivity, then web sockets are great. Otherwise long polling is imo the easiest to set up.
Because theyre just http requests
alr
so paypal sends me a request on my webhook endpoint (/api/webhooks/paypal/check-invoice)
after i validate all the stuff, i update the status of the document in mongodb (to "invoice paid")
on the frontend, i just need it to check status again and verify that the status is "invoice paid" so it can do the logic to render whats next.
how would long polling work in this scenario?
so when i recieve the paypal invoice, do i update the status in mongo, then send a request to a long poll route?
Sidenote: this would most easily be handled by a normal polling imo. Waiting 3 seconds here after payment is perfectly ok 🙃
Alternatively you could also improve simple polling by holding the request a bit on the server, and checking multiple times like so:
That way you skip the overhead of going to the server and back (which can often be an issue in serverless setups)
how would long polling work in this scenario?Happy to help a bit here, but what does your stack look like? ^^ If you want to do long-polling you'll need state. Super simple example of long polling to explain how it works (you can definitely use a library if you want): Server: Note: this is a simplified example and needs more work to be used in production.
thank you so much.
i jsut using nextjs fro both frontend and backend
isnt it better to do long polling?
so rn when a paypal invocie is paid, i get the event, verify it, update in mongodb, and then i need to let the poll know:
and then on my frontnend how could i make like all the stauts changes seamless and instant?
rn i just hjave a useeffect for every time the status state changes, the ui gets updated
so if im doing long poll, the code abovie is in a route handler (the paypal invoice paid one). what would i do to long poll
hey @Ian sorry for the ping. just wondering ^^
i jsut using nextjs fro both frontend and backendIn that case, I'm assuming all your requests are serverless, meaning you have no state on the server side (because every request lives in its own serverless function) To achieve long polling you need state, because the endpoint that receives the paypal event somehow needs to communicatie with the long polling request. Here are some options: Redis Using redis pub/sub, the endpoint that receives the paypal request can publish an event to redis, and the long polling endpoint can subscribe to events in redis. Mongo change streams I was looking around, and it seems that mongo supports "change streams" https://www.mongodb.com/docs/manual/changeStreams/ Never tried them, but perhaps they can be used by the polling endpoint to listen to events in mongo There are many other ways to achieve the same result, but realise that normal polling will still be the simplest solution. Make sure you ask yourself the question what the added benefit is of users being redirected away from the checkout page instantly, instead of having to wait 3 seconds
So should I do normal polling? Or how is it gonna work. Can I not like ping my frotnned state when I get smth from the webhook on the backend
If you are deployed to vercel that will not work because your backend only exists during the time a request is made. To use we sockets, server sent events, or long polling you need a server that will stay alive
Simplest solution is on the front end to wait a few seconds and send a requests, "was the payment successful yet?" Over and over again until you get a success response
at scale can that kill my vercel limits? im on the pro plan rn but yk just in case.
ye i am, so it isnt possible for my backend endpoint to send some data over to the frontend to update
Use the callback url, all on the front end, to act as the "trigger" to re-check the payment was completed
Full flow... User clicks pay, fills in details on PayPal site, complete payment, PayPal sends webhook and you update your db, user is redirected back to your site, once they land on your site, query your db to see that the purchase is complete, if not try again. If you have to try more than once you can probably add a fixed delay to account for anything delays on PayPal end
So rn, when the user submits the form we auto invoice them based on the details they put.
Then when the invoice is paid PayPal sends a webhook. There I would update that transaction in my db, and on the frontend I constantly check with a timer for any changes of that value right
You probably won't have to constantly check... I'm assuming that within a few seconds you might have a response from paypal
a few seconds from the user returning to you site that is
ye well it would depend on how fast the user pays the invoice. so ill probs set a max of 2 min, and then stop checking and cancel the transaction
That shouldn't matter as long as you only start checking once the callback url is redirected to
wdym?
the flow is:
user submits the form, we auto invoice their paypal. then we set a 2 min timer for the user to pay the invoice. if user pays, paypal sends us a webhook. we then update a db field. frontend continually checks updated field value in mongodb every 5 sec.
if the user does not pay, (2 min goes past), and no paypal webhook sent, then we cancel the invoice and update state to show an error on frontend
so basically i can't make my backend send a request to my frontend. the frontend needs to check continuously
When someone clicks pay with PayPal doesn't it take them off your site to pay?
They go to some PayPal.com website
They click pay and get redirected back to your website once it completes
There's essentially two callbacks, one client side and one server side
Both these callbacks should occur in sync, unless the user is being intentionally malicious, so the timings will line up and you shouldn't have to reach out to your database too many times, id assume under 15 seconds total....
no so we actually invoice them automtically with the paypal api when the form is submitted
so with the flow i sent above, is my appraoch right?
checking every 5 seconds for 2 min?
or any better way to optimize
I mean yea probably your only option when using serverless
Without breaking out and spinning up a server just for this
Hm ok thanks
Can I not do streaming or smth like that.
Your problem will be the vercel timeouts
They kill lambdas after a set amount of time
Depending on your payment tier, either way you get billed for the execution time
I've never done a payment like the way you are describing btw. Is this B2B?
kinda
we have pro tier. so 300 seconds
300 seconds is enough right. 2 min max per transaction.
Idk test it
Maybe just let the user hit a button to refresh
Hm ok