Translate

lunes, 24 de enero de 2022

Concurrencia en Clojure - parte 2


Seguimos con concurrencia en Clojure

Veamos un ejemplo que muestra cómo las estructuras de datos persistentes de Clojure significan que el estado mutable no puede escapar como lo hace en Java.

(def players (atom ()))

(defn list-players []

 (response (json/encode @players)))


(defn create-player [player-name]

  (swap! players conj player-name)

  (status (response "") 201))


(defroutes app-routes
  (GET "/players" [] (list-players))
  (PUT "/players/:player-name" [player-name] (create-player player-name)))

(defn -main [& args]
  (run-jetty (site app-routes) {:port 3000}))

Esto define un par de rutas: una solicitud GET a /players recuperará una lista de los jugadores actuales (en formato JSON) y una solicitud PUT a "/players/:player-name" agregará un jugador a esa lista. El servidor Embedded Jetty es multiproceso, por lo que nuestro código deberá ser seguro para subprocesos.

Veámoslo en acción. Podemos ejecutarlo desde la línea de comandos con curl:

$ curl localhost:3000/players

[]

$ curl -X put localhost:3000/players/john

$ curl localhost:3000/players

["john"]

$ curl -X put localhost:3000/players/paul

$ curl -X put localhost:3000/players/george

$ curl -X put localhost:3000/players/ringo

$ curl localhost:3000/players

["ringo","george","paul","john"]

Ahora veamos cómo funciona este código. El átomo de los jugadores :
  (def players (atom ()))
 se inicializa en la lista vacía (). Se agrega un nuevo jugador a la lista con conj :
  (swap! players conj player-name)
, y se devuelve una respuesta vacía con un estado HTTP 201 (creado). La lista de jugadores se devuelve mediante la codificación JSON del resultado de obtener el valor de los jugadores con @:
 (response (json/encode @players)))

Todo esto parece muy simple (y lo es), pero algo podría estar preocupándote algo al respecto. Tanto las funciones de listar jugadores como las de crear jugadores acceden a los jugadores. ¿Por qué este código no sufre el mismo problema que el código Java? ¿Qué sucede si un subproceso agrega una entrada a la lista de reproductores mientras otro lo itera y lo convierte a JSON? Este código es seguro para subprocesos porque las estructuras de datos de Clojure son persistentes.

Y que significa que sea persistente? y en el próximo post te cuento.