0

I want to build a php script for server side events (SSE), that will notify connected clients about changes in the server-side data.

For example, I have a CRUD API. When an API endpoint is called, it does its own stuff and then somehow notifies the SSE script about the changes, which sends it back to all connected clients.

To do this I do not need websockets, one-way connection to clients is sufficient.

The problem is that most of SSE scripts examples use infinite loops like while(true){ sendData(); sleep(1); }. I can check for any changes in the data inside that loop, but that is very inefficient, because these changes are not so frequent.

What I really want to achieve is a real async interface between API script and SSE script. I've seen ReactPHP for event-driven programming, but how do I combine it with the SSE script. How to trigger SSE to send an event from external PHP script?

user2531657
  • 339
  • 2
  • 9
  • you have to keep the PHP script running (hence the loop) but maybe you can first check for new data (e.g. in your database maybe, if that's where you store it) before you run sendData(). Or you can make it sleep longer, or whatever. – ADyson Oct 24 '19 at 13:08
  • Checking for changes before or inside loop is not feasible. I want something like [this](https://github.com/clue/reactphp-eventsource#quickstart-example), but in a different manner like send on message `$app->on('message', sendSSE())` – user2531657 Oct 24 '19 at 13:44
  • that is still basically implementing a loop. See the "loop->run()" at the end? It's just not your loop. Why is checking for changes inside the loop "not feasible" exactly? You didn't explain. You haven't really said where the changes come from, or in what format. Anyway basically the GitHub project is just an SSE client for PHP. So if you have another SSE stream from which events are coming, you can use it. But then again you could just get the browser to subscribe to it directly. – ADyson Oct 24 '19 at 13:49
  • Let's say I have an API endpoint /delete/{id}/ that executes delete.php and removes an item with {id} from a database. Now I want to notify all other clients connected to the servers (not the one that called the API), that the {id} has been deleted. I can issue an SSE event that will update user interface accordingly. The problem how do I push this "delete event" from delete.php to SSEserver.php (that runs in a loop)? – user2531657 Oct 24 '19 at 13:55
  • Well you could have a background "queue" of events, which the endpoint can publish to, and the SSE script can subscribe to. There are a lot of potential technologies you could use for that (MSMQ on Windows, or some cloud event service, there maybe others too). Or more simplistically the SSE script could periodically run a database query to check for any new records it hasn't seen before. The result is very similar. The SSE script still has to run in an infinite loop though to either wait for events, or go looking for them, whichever you choose. – ADyson Oct 24 '19 at 14:09
  • P.S. if you go the database route, if you want SSE to emit more events than just deletion, you could have a separate "event queue" table and set triggers on the DB so that all sorts of changes cause a row to be created in the queue table saying what has happened. It would be a useful audit trail, too. And then the SSE script can periodically query that table and look for the event types it's interested in, and hasn't found before, and then send them out to its subscribed clients. And with that you've basically implemented your own simple pub-sub messaging system. – ADyson Oct 24 '19 at 14:12
  • That's definitely an option, but I was looking for a more elegant async event based solutions (though php is not be best option for such things). – user2531657 Oct 24 '19 at 14:19
  • well you can do that, but you need to involve a separate product to act as the message broker. I guess you could implement your own broker in PHP (running from the commandline), but it's usually best not to re-invent the wheel if you can avoid it. Whatever you use, _something_ has to run in the background somewhere to act as the middle-man between the API endpoint and the SSE script, whether that's a database or some other technology. You can't do the whole thing in the context of stateless HTTP requests, as I'm sure you've already grasped. – ADyson Oct 24 '19 at 14:24
  • https://learn.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber describes the pattern quite nicely in the abstract. (In that scenario, your SSE script is one of the "subscriber" objects in the diagram. Of course the SSE script itself is also a publisher and has its own subscribers, so it's almost a proxy for the original events, just changing the channel technology to be browser-friendly. I'm just noting that so you don't get confused about which component is which in the diagram.) – ADyson Oct 24 '19 at 14:26
  • The main reason I suggested to use the database as (effectively) the broker / maintainer of the message queue is that, unless you need to do this at very large scale to service the traffic on your site (and you implied in your question that this isn't the case), it's just well...simpler. You can use tech you're already familiar with and there isn't another product and interface to maintain. The subtle difference is your "subscriber" has to go and poll for events instead of having them pushed, but in practice, at low volume, it won't make much difference. – ADyson Oct 24 '19 at 14:43
  • P.S. to go back to (what I think was, essentially) your original point - you felt the "infinite loop" in the SSE script was inefficient. In a way yes, it's not so great to have something which is infrequently used running all the time but... a) if it stops running, it won't be able to listen for events coming from the API endpoint, and b) if it stops running, browser clients will lose their connection to it. – ADyson Oct 24 '19 at 14:45
  • One thing I'm not quite certain of though (having not used SSE in anger) is if PHP will spin up a separate instance of the SSE script for every subscribed browser window. I think it might, just as it would run a separate instance of a regular PHP script for each HTTP request received. But they probably stop when the browser window hosting the client closes. I don't know for sure, I'm sure you can find this kind of thing out by testing or from other research. – ADyson Oct 24 '19 at 14:46
  • I made a reactphp scaffolding application with SSE some months ago. You can look into it here: https://github.com/jsmmo/jsmmo the run.php and the SSEConnectionHelper.php are the most important lines you are looking for. – user3655829 Oct 25 '19 at 08:29
  • 1
    I think we'll skip ReactPHP at the moment, but use Redis streams as a message broker, that will fan-out messages to multiple `SSEserver.php` scripts running the loop and waiting for new messages. Haven't tried that yet, but in theory that should work. – user2531657 Oct 26 '19 at 12:16

0 Answers0