Categories
.NET

Notificaciones en PostgreSQL

Desde la versión 8 de este magnífico ORDBMS, existe un mecanismo que permite enviar y recibir notificaciones de manera muy simple.

code:

test=# LISTEN foo;
LISTEN
test=# NOTIFY foo;
NOTIFY
Notificación asíncrona «foo» recibida del proceso de servidor con PID 8872.
test=#

Esta característica -como menciona la documentación- es especialmente útil cuando existen procesos que deben estar englobados por una transacción, ejm. enviar un mail luego de la ejecución satisfactoria de un conjunto de procesos críticos.

A continuación un pequeño ejemplo realizado con el proveedor Npgsql, que implementa la caracterísca mencionada.

csharp:

// Encargado de 'escuchar' las notificaciones
using System;
using Npgsql;
using System.Net.Mail;
using System.Net;

namespace listener
{
    class Program
    {
        static void Main(string[] args)
        {
            NpgsqlConnection connection =
                new NpgsqlConnection("uid=alex;pwd=***;server=localhost;encoding=unicode;SyncNotification=true;database=test;");

            connection.Notification += new NotificationEventHandler(connection_Notification);

            // Escuchar las notificaciones con el nombre 'proceso_largo'
            using (NpgsqlCommand command =new NpgsqlCommand("LISTEN proceso_largo;", connection))
            {
                connection.Open();
                command.ExecuteNonQuery();
            }

            Console.WriteLine("Esperando notificaciones...");
        }

        static void connection_Notification(object sender, NpgsqlNotificationEventArgs e)
        {
            Console.WriteLine("Notificación Recibida: {0}\t{1}", e.Condition, e.PID);

            // Hacer algo útil

            SmtpClient client =new SmtpClient("smtp.empresa.com");
            client.Credentials =new NetworkCredential("usuario@empresa.com", "password");

            client.Send(
                "aplicacion_x@empresa.com",
                "logs@empresa.com",
                "Notificación aplicación_x",
                "Notificación: " + e.Condition + "\tPID : " + e.PID // ...
                );
        }
    }
}

Un cliente cualquiera:

csharp:

using System;
using Npgsql;
using System.Threading;

namespace app
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Iniciar Aplicación - Presione una tecla...");
            Console.Read();

            using (NpgsqlConnection connection =
                new NpgsqlConnection("uid=alex;pwd=***;server=localhost;encoding=unicode;database=test;"))
            {
                NpgsqlTransaction transaction = null;

                try
                {
                    connection.Open();
                    transaction = connection.BeginTransaction();

                    NpgsqlCommand command =new NpgsqlCommand("select current_date;", connection, transaction);

                    Console.WriteLine("Recuperando la fecha");
                    command.ExecuteScalar(); // hacer algo

                    Console.WriteLine("Enviando notificación - Transacción NO 'comprometida'.");
                    command.CommandText = "NOTIFY proceso_largo;";
                    command.ExecuteNonQuery(); // No ejecuta la notificación

                    // Continúa la transacción
                    Thread.Sleep(2000);
                   
                    transaction.Commit();
                    Console.WriteLine("Transacción 'comprometida', recien se envía la notificación 'proceso_largo'");
                }
                catch (NpgsqlException)
                {
                    if (transaction != null)
                        transaction.Rollback();
                    throw;
                }
            }
            Console.Read();
        }
    }
}

Además de las cosas mencionadas sobre esta característica de PostgreSQL, también podría servir como un mecanismo para que el Cache tenga datos coherentes.

Nota: Disculpen si encuentran malas prácticas de programación :-).

Elementos utilizados