Carlos Alves Jorge
Carlos Alves Jorge

Reputation: 1985

How can I use server sent events with trigger?

I'm thinking about migrating my notification system which uses ajax pooling to server sent events in a way similar to:

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$sql = "SELECT name,body FROM notification where id='user1'";
...
echo 'data: ' . json_encode($arrayResult) . "\n\n";
$conn->close();
flush();
?>

My question though is that this seems to be constantly making queries to the DB (in similar way to ajax pooling) which seems can become quite intensive.

What would you suggest to alter on the server side code so that it's not constantly pooling the database but would only query it after a notification was inserted?

Upvotes: 0

Views: 1325

Answers (2)

BeetleJuice
BeetleJuice

Reputation: 40896

What's happening is that by default, the browser will reopen the connection after 3 seconds and your script will run once more and query the DB. Another problem I see is that your sql query will always return results even if there is no new notification since the last check. A better query would select only recent notification. You have three simple options

Set retry parameter

By sending the browser a retry value with the first message, you control how long the browser will wait to reopen the connection:

echo "retry: 60000\n"; // reopen the connection in 60 seconds
echo 'data: ' . json_encode($arrayResult) . "\n\n";

Use an infinite loop with a pause

Instead of letting your script quickly execute to the end and having the browser reopen the connection 3 seconds later, you can do your DB check in a loop whose frequency you control

set_time_limit(0); // remove any time limit to script execution

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header("Connection: keep-alive");

while(true){
  $sql = 'SELECT...'; // alter your query to only fetch recent notifications
  // fetch results and put in $arrayResult
  if(!empty($arrayResult)) echo 'data: ' . json_encode($arrayResult) . "\n\n";
  ob_flush(); flush();
  sleep(60); // sleep for 60 seconds
}

Use a memory cache

A memory cache can store notifications in one script execution and retrieve them in the other. So your script would:

  • check the cache for a notification belonging to the current user
  • if found, echo the notification and delete it from the cache (or set a SENT flag)
  • else sleep, then loop

I've used memcache but there are others. This does require you to install new software on the web server, but it's probably what I would do.

Upvotes: 2

CCH
CCH

Reputation: 1536

In that case you would need to intercept the notification directly in the code that inserts it in the database (thus short-circuiting the database).

A more conventional way of doing this would be to use a message broker.

Upvotes: 0

Related Questions