Smart Polling

Sep 20 10:04

Livewire aims to be thrifty when it comes to resource usage (ajax requests being the biggest). Here is an example of a little feature I recently implemented with a really clever extra bit thrown in there.

Transcript:

[00:00:00] Caleb: All right. I got a problem for you. So we're going to talk about polling in live lawyer Pol ing not pulling but pulling and so first the concept of polling is instead of using something like Pusher websockets to. Events from the server side you use polling to pull the server on an interval like every second or so for new for news from the server this way you don't have to deal with server-side server-sent events websockets all of that extra craziness that gets added to your app.

You can just simply use Ajax inside some sort of time interval and pull for. Common use cases for this are maybe like if you have like a notification button in the top like navbar that has a little alert thing like a little red dot if there's new notifications that could be a websocket driven thing or you could just pull every 10 seconds or so five or ten seconds.

[00:01:00] You know to an end point to just see if there's any new notifications. So anyway, it's pretty common practice and it's been used for a long time and I still like it because it's really simple I prefer it over Pusher until you know, my needs are big. Anyway, so this all came about because I was showing David Hemphill Livewire like way back when and he's like, how would I accomplish this in Live Wire?

And he had toaster notification was a toaster notifications know it was like he was building. I don't know if it was the something for the 4J or for the for GUI or Nova or chipper probably chipper and he needed to know the status of a deployment or something like that. He needed a button to go from red to Green as you know as the progress of something sort of progress.

And he said how would I comes in Live Wire and I was like, okay. I need to make polling. I need to make some sort of feature to pull easily with live where because the potential is totally there. So I added this directive called wire: Pole. So anywhere inside of your Livewire component, let's say you have let's [00:02:00] say live or components just a div and inside that div or on that that route give you a Dwyer: pull and then inside of it you Echo out the current time in PHP and you rendered on the page now, I think the default is like 2 or 5 seconds.

I can't remember every two or five seconds. I think it's too. Every two seconds the time we'll update because Live Wire every will stood like a JavaScript set interval and fire off a request to the server get the new Don with the new date time and swap it into the page. So it's a pretty cool feature and I just kind of left it in there.

It was it was documented pretty poorly fast-forward till maybe a month ago. I don't know a couple weeks ago probably till cross. He's a till he corrects me with his last name. It's like couscous till. Bruce I don't know. Sorry till he's a friend of mine great guy till is like number five contributor to laravel Corey's been, you know pitching in and open source for a long long [00:03:00] time.

So he got into live wearing he pinged me and he said hey, I want to use a live wire for this. Is it good for this? And basically he wanted to make a little messaging system where you could have like conversations? And then other users could add messages and it would get added if a new message was there and he said I would need something.

You know, this Library support web sockets blah blah blah and I said well if you use Pusher live where does support level Echo but what you I think you could probably get away with is just pulling and he's like well one dude, I didn't even find it and I look through all the docs. So I updated the dock so that it's like a first-class citizen.

Feature and then he's like yeah that could probably work. So we got on a call and we hacked it out and we got the implementation working which was really cool. But he's like, you know, dude honestly, this is probably maybe a little bit Overkill but there's just something about having a machine having everybody's tab just sitting there.

Well at the time the default was like 500 milliseconds. So every half a [00:04:00] second an Ajax request was being sent he's like if they have five tabs open. That's a zillion Ajax request like that server load is just too much. So even if I slow it down, I just feel like people are gonna have all these tabs open.

He's like, I wonder if you could do something to make the pulling lie dormant. So we immediately Googled for a page visibility API. That's what it's called. We didn't know that at the time but it exists. I'm like I bet exist. I bet something and you know in. JavaScript ER you know HTML. Yeah JavaScript the JavaScript spec exists.

That's that gives you an API for detecting if a browser is inactive, like if a user switches tabs, and there is it's called the page visibility API and it's a little event that gets fired on the document. So you do document dot add event listener for I think it's called visibility change and then you get document dot hidden is a Boolean value just in.

In your browser that is true or false depending on if the browser is hidden. So you set up an event listener and [00:05:00] you can you know check on document dot hidden to get your value if the browser tab is hidden or not. So this is something that kind of lingered in the background that to him was like a deal breaker.

Like I need something to I need it to do this before I can implement this and I just got to it yesterday. I was like, you know what? I'm just going to spike this out. I bet it'll take me five minutes. And I was right it was very simple feature. So here was my Approach their I guess I'll first say what what might have been a knee-jerk reaction approach is to somehow remove.

So when wire when Live Wire to text wire pole on an element, it will register a set interval. It will register a set interval that fires off an Ajax request on Livewire every you know by default. Like I said to two seconds I think so that's just running so you could start you could delete that set interval.

I think I think you can clear set interval like you can clear settimeout. So maybe [00:06:00] that would be an option is like register this this listener so that when the page is not visible destroy that interval then when it becomes visible recreate the interval, so I wanted something a little bit simpler.

So what I decided to do was to create a global state so I have a global Livewire store in JavaScript. It's like a Singleton or I store all the state. It's anything that's common to all live where components. It's like the god Livewire store. It's a Singleton. Like I said, So I can put Global State on that.

So I put a little piece of global State called Live Wire is in background that defaults to false and then on boot. I registered this listener that listens for the visibility change and I set that to true or false. Now inside my set interval where that registers when live or detects wire pole. It's going to just do a check and say hey is Live Wire in the background or in the foreground?

If it's in the background just return return early, like don't get to actually fire the Ajax request. So one benefit of this actually this is like what I love about a lot of these live or [00:07:00] JavaScript problems is your really zooming in on a problem like. You're going really deep into like the frame by frame details of a problem.

So what I mean by that is so this means that if if it's let's say it's every 5 Seconds that this Ajax request gets sent if you leave the tab after 3 seconds. It's going to get to that fight that fifth second. It'll be in the background and it won't fire the Ajax request. When you go back to visit the tab, there's only like, you know, you can figure out the percentage when you come back to visit this tab.

The interval is still running. So the chances of you hitting it at the perfect Mark are really Slim meaning that it's not going to be like you come back to the page and then you have to wait 5 seconds for a new poll. It's like it'll probably be some amount of time already progressed through that hole.

When you come back to the page so likely because that was one of his Hang-Ups is like well, then what if you come back to the page and then you're flooded with all this new info, you know, if you have to [00:08:00] wait like let's say it's a 10 second pulley have to wait 10 seconds. When you come back to the page.

It's unlikely that it would be the full ten seconds. But that aside somebody in the GitHub repository. This is a GitHub issue. Somebody was like Hey, wouldn't it be cool if you slow down the polling? Instead of just cut it off just slow it way down while it's in the background and I was like, yeah, that would be cool.

And my initial reaction was yeah, but that'd be super hard. Like I would have to change the interval of a set interval and then change it back when page visibility. But I was recently inspired by if you listen to no plans to merge my other podcast you've heard us talk about the sessions Lottery.

This is the thing Taylor uses a lottery like a random chance thing in laravel to clear to do the session garbage collection so every. Approximately hundredth request gets tasked with clearing the whole app session garbage. But so I decided to apply the same principle that instead in my set interval for the [00:09:00] polling instead of just firing the the Ajax request or instead of just sorry.

Just checking to see if live wires in background and then cutting off Ajax requests. If it is I do this is literally the code it's like if is in background. And and then I do math dot random to get a number between 0 and 1 it gives you a decimal between 0 and 1 if math dot random is greater than .95 and what that does is it like couches my conditional with an extra check for five percent.

So it's basically like 5% of the time. Oh, no, I'm sorry. I think it's an or statement if it's in the background. Right right now it's an and if it's in the background and math dot random is greater than .95 then block the requests or less than point. I can't think of it right now, whatever. I'm bullying impaired, but the concept is that I added in this little buffer so that if it's in the background five percent of requests are slipped through so that you can still [00:10:00] pull little by little oh my gosh.

I'm at 10 minutes. I hope you enjoyed this. Thanks. Bye.