Monday, April 30, 2012

Advantages of PostgreSQL Asynchronous Events

Communications is key among processes and threads.  We have IPC's and signals for local system communications but what to do for processes running on different hosts?  There's a host of answers for this ranging from JMS to Jabberd but I was looking for something with the following parameters

  • uses a service already in my environment,
  • message is temporary, and
  • is automatically sent to all listening.
We have a LAPP stack (Linux, Apache, ActiveMQ, PostgreSQL & PHP).  Might argue ActiveMQ would work and yes it would however it's abused already and the messages aren't always as timely as they ought to be.  Also, the purpose of this task was to find a fallback means to communication should ActiveMQ die (which has been known to happen).

Decided on the PostgreSQL NOITFY - LISTEN pair to send simple asynchronous event notifications.  All that's required is a database connection (already there) to a shared database (already done).  The PHP code is pretty straightforward.  Here's a snippit...


#!/usr/bin/php
<?php

// Open some connections to our database
$dbh1 = pg_connect("dbname=postgres");
$dbh2 = pg_connect("dbname=postgres");
$dbh3 = pg_connect("dbname=postgres");

// Prime the connection
Database::asyncListen($dbh2, 'listen_test');
Database::asyncListen($dbh3, 'listen_test');

// Send notification
Database::asyncSend($dbh1, 'listen_test');

// Listen for notification on current connections
Database::asyncListen($dbh2, 'listen_test');
Database::asyncListen($dbh3, 'listen_test');

// Test connection signing on after the event
$dbh4 = pg_connect("dbname=postgres");
Database::asyncListen($dbh4, 'listen_test');

class Database {
  public function asyncSend($conn, $event) {
     pg_query($conn, "NOTIFY {$event};");
     echo "event created\n";
  }

  public function asyncListen($conn, $event) {
     pg_query($conn, "LISTEN {$event};");
     if ( pg_get_notify($conn) !== false ) {
       echo "event '{$event}' registered\n";
     } else {
       echo "nothing\n";
     }
  }
}
?>

Here's the output:
nothing
nothing
event created
event 'listen_test' registered
event 'listen_test' registered
nothing

What's this good for? As we race towards distributed computing there has to be a means to communicate effectively. Such communications within PostgreSQL is handy in that LISTEN is incredibly light thus a body to the message / event is not necessary. Multiple LISTEN's can be executed looking for many events for many things. The name is specific to the message. Rather than multiple constant SELECT's on a table looking for a record, using NOTIFY can tell the code when to check the table.

Just one of those little discoveries I felt the need to scream from the rooftops.