Concurrencia en PHP

Seguro que os habéis encontrado alguna vez con problemas de concurrencia en PHP, pensadlo por un momento, seguro que tenéis muchos casos y la verdad es que no hay soluciones sencillas en este lenguaje para poder proteger código crítico.

Imaginaros una API que gestione un saldo de puntos, con una llamada que realice por ejemplo:

  1. Una lectura de Base de datos para obtener el saldo actual
  2. Operaciones de cálculo
  3. Una escritura en la base de datos con el nuevo resultado.

Si a esta API se le pueden lanzar múltiples peticiones asíncronas, es fácil que en algún momento se produzcan problemas y alguna de las operaciones sean sobrescritas con el resultado de otra.

Os voy a contar dos formas con las que he solucionado el problema.

Función flock() de PHP

Con esta función podemos bloquear y desbloquear el acceso a un archivo. Solo necesitamos pasarle un manejador de un archivo y la operación que queremos realizar:

  • LOCK_SH para adquirir un bloqueo compartido (lectura).
  • LOCK_EX para adquirir un bloqueo exclusivo (escritura).
  • LOCK_UN para liberar un bloqueo (compartido o exclusivo).

A continuación os pongo un ejemplo de uso:

Lo que estamos haciendo, es comprobar si el archivo está bloqueado. Si está libre, entonces flock bloquea el archivo, y ya podemos hacer las operaciones que necesitemos con seguridad. Al finalizar desbloqueamos el archivo para que otro proceso pueda tomar el bloqueo.

Mientras el fichero está bloqueado el resto de procesos esperan en cola a que se libere el bloqueo.

Se puede añadir una opción adicional que evitará que el proceso espere cuando se solicita un bloqueo de archivo. Esto significa que si el bloqueo de archivo no está disponible, flock () devolverá un valor falso, en lugar de esperar a desbloqueo.

 

Librería “malkusch/lock

Hace unos meses encontré esta fantástica librería que resuelve muy bien este problema y además es muy fácil de utilizar. Enhorabuena por su trabajo a Markus Malkusch su creador, gracias 🙂

Aquí podéis ver un ejemplo de uso:

Este método garantiza que el código sólo se ejecuta por un proceso a la vez. Otros procesos tienen que esperar hasta que esté disponible. El código crítico puede lanzar una excepción, lo que liberaría el bloqueo también.

Además ofrece varias implementaciones para gestionar los bloqueos.

Su documentación está muy bien, os invito a que veáis cómo funciona e investiguéis todas las opciones que ofrece.

Espero que esta información sea de utilidad, hasta la próxima 🙂