<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>RandomBitsOnFire</title>
	<atom:link href="https://randombitsonfire.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://randombitsonfire.com</link>
	<description>Home</description>
	<lastBuildDate>Sun, 15 Mar 2026 15:43:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://randombitsonfire.com/wp-content/uploads/2024/08/cropped-favicon512x512-32x32.png</url>
	<title>RandomBitsOnFire</title>
	<link>https://randombitsonfire.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Comenzando con Arduino</title>
		<link>https://randombitsonfire.com/sin-categoria/comenzando-con-arduino/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=comenzando-con-arduino</link>
					<comments>https://randombitsonfire.com/sin-categoria/comenzando-con-arduino/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 15 Mar 2026 23:00:00 +0000</pubDate>
				<category><![CDATA[Sin categoría]]></category>
		<guid isPermaLink="false">https://randombitsonfire.com/?p=190</guid>

					<description><![CDATA[<p>Si alguna vez has querido controlar luces, motores, sensores o crear tus propios dispositivos electrónicos, tarde o temprano te encontrarás con Arduino. Arduino es una de las plataformas más populares para aprender electrónica y sistemas embebidos. Parte de su éxito viene de algo muy simple: hace que trabajar con microcontroladores sea mucho más fácil. En [&#8230;]</p>
<p>The post <a href="https://randombitsonfire.com/sin-categoria/comenzando-con-arduino/">Comenzando con Arduino</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Si alguna vez has querido <strong>controlar luces, motores, sensores o crear tus propios dispositivos electrónicos</strong>, tarde o temprano te encontrarás con <strong>Arduino</strong>.</p>



<p>Arduino es una de las plataformas más populares para aprender electrónica y sistemas embebidos. Parte de su éxito viene de algo muy simple: <strong>hace que trabajar con microcontroladores sea mucho más fácil</strong>.</p>



<p>En este post vamos a ver:</p>



<ul class="wp-block-list">
<li>Qué es realmente un microcontrolador</li>



<li>Un poco de historia de Arduino</li>



<li>Qué puede hacer técnicamente</li>



<li>Qué placas existen</li>



<li>Y qué alternativas similares hay</li>
</ul>



<h1 class="wp-block-heading">Qué es un microcontrolador (explicado fácil)</h1>



<p>Un <strong>microcontrolador</strong> es básicamente <strong>un pequeño ordenador dentro de un chip</strong>.</p>



<p>Mientras que un PC tiene procesador, memoria RAM, almacenamiento y puertos, un microcontrolador <strong>integra todo eso dentro de un único circuito</strong>.</p>



<p>Normalmente incluye:</p>



<ul class="wp-block-list">
<li>CPU</li>



<li>memoria RAM</li>



<li>memoria flash (donde va el programa)</li>



<li>pines de entrada/salida</li>



<li>temporizadores</li>



<li>interfaces de comunicación</li>
</ul>



<p>Todo esto permite <strong>controlar hardware directamente</strong>.</p>



<p>Ejemplos típicos de uso:</p>



<ul class="wp-block-list">
<li>encender LEDs</li>



<li>leer sensores de temperatura</li>



<li>controlar motores</li>



<li>manejar pantallas</li>



<li>comunicarse con otros dispositivos</li>
</ul>



<p>Los microcontroladores están en todas partes:</p>



<ul class="wp-block-list">
<li>electrodomésticos</li>



<li>coches</li>



<li>juguetes</li>



<li>routers</li>



<li>relojes digitales</li>
</ul>



<p>Y, por supuesto, en placas como Arduino.</p>



<h1 class="wp-block-heading">Un poco de historia de Arduino</h1>



<p>Arduino nació en <strong>2005</strong> en el <strong>Interaction Design Institute Ivrea</strong> en Italia.</p>



<p>El objetivo era sencillo: <strong>crear una plataforma barata y fácil de usar para estudiantes de diseño</strong>, que muchas veces necesitaban interactuar con hardware pero no tenían formación profunda en electrónica.</p>



<p>El proyecto fue impulsado por personas como <strong>Massimo Banzi</strong>, que buscaban una alternativa accesible a las herramientas profesionales que eran caras y complejas.</p>



<p>Las claves del éxito de Arduino fueron:</p>



<ul class="wp-block-list">
<li>hardware open-source</li>



<li>entorno de programación sencillo</li>



<li>enorme comunidad</li>



<li>miles de tutoriales y librerías</li>
</ul>



<p>Con el tiempo se convirtió en <strong>uno de los estándares educativos de electrónica</strong>.</p>



<p>Una placa Arduino es básicamente <strong>un microcontrolador montado en una placa con todo lo necesario para usarlo fácilmente</strong>.</p>



<p>Por ejemplo la popular <strong>Arduino Uno</strong> incluye:</p>



<ul class="wp-block-list">
<li>microcontrolador</li>



<li>regulador de voltaje</li>



<li>puerto USB</li>



<li>pines de entrada y salida</li>



<li>reloj interno</li>
</ul>



<p>Esto permite programarla desde un PC y conectarla a sensores o actuadores.</p>



<h1 class="wp-block-heading">Capacidades técnicas (resumen)</h1>



<p>Aunque depende del modelo, muchas placas Arduino comparten características similares.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Característica</th><th>Descripción</th></tr></thead><tbody><tr><td>CPU</td><td>microcontrolador AVR o ARM</td></tr><tr><td>Frecuencia</td><td>~16 MHz</td></tr><tr><td>Memoria Flash</td><td>32 KB aprox</td></tr><tr><td>RAM</td><td>~2 KB</td></tr><tr><td>Pines digitales</td><td>14</td></tr><tr><td>Pines analógicos</td><td>6</td></tr><tr><td>Comunicación</td><td>UART, SPI, I2C</td></tr><tr><td>Alimentación</td><td>5V o 3.3V</td></tr></tbody></table></figure>



<p>Estas capacidades pueden parecer pequeñas comparadas con un PC, pero son <strong>más que suficientes para miles de proyectos electrónicos</strong>.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="800" height="559" src="https://randombitsonfire.com/wp-content/uploads/2026/03/aduino-pinout-uno.webp" alt="" class="wp-image-234" srcset="https://randombitsonfire.com/wp-content/uploads/2026/03/aduino-pinout-uno.webp 800w, https://randombitsonfire.com/wp-content/uploads/2026/03/aduino-pinout-uno-300x210.webp 300w, https://randombitsonfire.com/wp-content/uploads/2026/03/aduino-pinout-uno-768x537.webp 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<h1 class="wp-block-heading">Qué puedes hacer con Arduino</h1>



<p>Algunos proyectos típicos:</p>



<ul class="wp-block-list">
<li>estaciones meteorológicas</li>



<li>robots pequeños</li>



<li>sistemas de riego automáticos</li>



<li>control domótico</li>



<li>instrumentos MIDI</li>



<li>displays LED</li>



<li>control de drones o motores</li>
</ul>



<p>La clave es que Arduino <strong>interactúa directamente con el mundo físico</strong>.</p>



<h1 class="wp-block-heading">Otros microcontroladores similares</h1>



<p>Arduino es muy popular, pero no es la única opción. Existen otras plataformas del mismo nivel que también se utilizan mucho.</p>



<h3 class="wp-block-heading">Raspberry Pi Pico</h3>



<p>Basada en el chip <strong>RP2040</strong> desarrollado por <strong>Raspberry Pi Ltd</strong>.</p>



<p>Ventajas:</p>



<ul class="wp-block-list">
<li>más potencia</li>



<li>doble núcleo</li>



<li>más RAM</li>
</ul>



<p>Muy popular para proyectos DIY.</p>



<h3 class="wp-block-heading">ESP32</h3>



<p>Fabricado por <strong>Espressif Systems</strong>.</p>



<p>Características clave:</p>



<ul class="wp-block-list">
<li>WiFi integrado</li>



<li>Bluetooth</li>



<li>mucha más potencia que Arduino clásico</li>
</ul>



<p>Es una de las opciones favoritas para <strong>IoT</strong>.</p>



<h3 class="wp-block-heading">STM32</h3>



<p>Familia de microcontroladores de <strong>STMicroelectronics</strong>.</p>



<p>Ventajas:</p>



<ul class="wp-block-list">
<li>arquitectura ARM</li>



<li>mucho rendimiento</li>



<li>usados en industria</li>
</ul>



<p>Placas comunes: <strong>STM32 Nucleo</strong>.</p>



<h1 class="wp-block-heading">¿Por qué Arduino sigue siendo tan popular?</h1>



<p>Aunque existan placas más potentes, Arduino sigue teniendo ventajas claras:</p>



<ul class="wp-block-list">
<li>curva de aprendizaje muy baja</li>



<li>enorme comunidad</li>



<li>miles de librerías</li>



<li>documentación muy accesible</li>
</ul>



<p>Para alguien que empieza, <strong>es probablemente la forma más rápida de entrar en el mundo de los sistemas embebidos</strong>.</p>



<h1 class="wp-block-heading">Recursos para aprender más</h1>



<p>Si quieres profundizar, estas fuentes son muy recomendables:</p>



<ul class="wp-block-list">
<li>documentación oficial de <strong><a href="https://www.arduino.cc/" title="">Arduino</a></strong></li>



<li>comunidad de <strong><a href="https://hackaday.com/" title="">Hackaday</a></strong></li>



<li>tutoriales de <strong><a href="https://www.adafruit.com/" title="">Adafruit Industries</a></strong></li>



<li>guías de <strong><a href="https://www.sparkfun.com/" title="">SparkFun Electronics</a></strong></li>



<li>ejemplos de <strong><a href="https://www.espressif.com/" title="">Expressif </a></strong></li>
</ul><p>The post <a href="https://randombitsonfire.com/sin-categoria/comenzando-con-arduino/">Comenzando con Arduino</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://randombitsonfire.com/sin-categoria/comenzando-con-arduino/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP y PHP-FPM con Apache: diferencias</title>
		<link>https://randombitsonfire.com/programacion/back/php-y-php-fpm-con-apache-diferencias/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-y-php-fpm-con-apache-diferencias</link>
					<comments>https://randombitsonfire.com/programacion/back/php-y-php-fpm-con-apache-diferencias/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 09 Mar 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[Arquitectura]]></category>
		<category><![CDATA[Back]]></category>
		<category><![CDATA[Programacion]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[FPM]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Servidores]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://randombitsonfire.com/?p=144</guid>

					<description><![CDATA[<p>Si estás desarrollando aplicaciones web con PHP, seguramente te habrás encontrado con distintos métodos para ejecutar el código: mod_php, PHP-FPM, y cómo Apache los maneja. Vamos a desglosarlo. 1. PHP tradicional con Apache (mod_php) 2. PHP-FPM (FastCGI Process Manager) Requiere monitoreo de los pools de procesos para evitar saturación. Qué es: PHP-FPM es un gestor [&#8230;]</p>
<p>The post <a href="https://randombitsonfire.com/programacion/back/php-y-php-fpm-con-apache-diferencias/">PHP y PHP-FPM con Apache: diferencias</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Si estás desarrollando aplicaciones web con <strong>PHP</strong>, seguramente te habrás encontrado con distintos métodos para ejecutar el código: <strong>mod_php</strong>, <strong>PHP-FPM</strong>, y cómo Apache los maneja. Vamos a desglosarlo.</p>



<h3 class="wp-block-heading">1. PHP tradicional con Apache (mod_php)</h3>



<ul class="wp-block-list">
<li><strong>Qué es:</strong> <code>mod_php</code> es un módulo de Apache que permite ejecutar código PHP directamente dentro del proceso del servidor web.</li>



<li><strong>Cómo funciona:</strong> Apache carga el intérprete de PHP como parte de sus procesos. Cada petición HTTP que requiere PHP es procesada dentro del mismo proceso de Apache.</li>



<li><strong>Ventajas:</strong>
<ul class="wp-block-list">
<li>Simplicidad: fácil de configurar.</li>



<li>Integración directa: PHP puede acceder a variables de Apache y módulos internos.</li>
</ul>
</li>



<li><strong>Desventajas:</strong>
<ul class="wp-block-list">
<li>Cada proceso de Apache carga PHP completo, lo que aumenta el consumo de memoria.</li>



<li>No es tan eficiente en entornos con muchas conexiones concurrentes.</li>
</ul>
</li>
</ul>



<figure class="wp-block-image aligncenter size-full"><img decoding="async" width="459" height="292" src="https://randombitsonfire.com/wp-content/uploads/2026/02/image-1.png" alt="" class="wp-image-218" srcset="https://randombitsonfire.com/wp-content/uploads/2026/02/image-1.png 459w, https://randombitsonfire.com/wp-content/uploads/2026/02/image-1-300x191.png 300w" sizes="(max-width: 459px) 100vw, 459px" /></figure>



<h3 class="wp-block-heading">2. PHP-FPM (FastCGI Process Manager)</h3>



<p>Requiere monitoreo de los pools de procesos para evitar saturación.</p>



<p><strong>Qué es:</strong> PHP-FPM es un gestor de procesos FastCGI para PHP. Funciona como un servicio independiente que Apache llama para ejecutar scripts PHP.</p>



<p><strong>Cómo funciona:</strong></p>



<p>Apache recibe la petición HTTP.</p>



<p>Si es un archivo PHP, Apache lo redirige a PHP-FPM mediante <strong>FastCGI</strong> (usualmente usando <code>mod_proxy_fcgi</code>). <strong>En versiones de Linux Alpine se encuentra incluido en el mod_proxy</strong>.</p>



<p>PHP-FPM procesa el script y devuelve la respuesta a Apache.</p>



<p><strong>Ventajas:</strong></p>



<p>Manejo eficiente de procesos: PHP-FPM mantiene pools de procesos listos para servir solicitudes.</p>



<p>Mejor rendimiento en sitios con alta concurrencia.</p>



<p>Permite ejecutar diferentes versiones de PHP para distintos sitios.</p>



<p>Mejor aislamiento de procesos y control de recursos.</p>



<p><strong>Desventajas:</strong></p>



<p>Configuración más compleja.</p>



<figure class="wp-block-image aligncenter size-full"><img decoding="async" width="562" height="319" src="https://randombitsonfire.com/wp-content/uploads/2026/02/image-2.png" alt="" class="wp-image-219" srcset="https://randombitsonfire.com/wp-content/uploads/2026/02/image-2.png 562w, https://randombitsonfire.com/wp-content/uploads/2026/02/image-2-300x170.png 300w" sizes="(max-width: 562px) 100vw, 562px" /></figure>



<h3 class="wp-block-heading">3. Cómo Apache gestiona PHP con FPM</h3>



<p>Apache ya no ejecuta PHP directamente. Usa <strong>mod_proxy_fcgi</strong> o <strong>mod_fastcgi</strong> para comunicarse con PHP-FPM:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;FilesMatch .php$>
    SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost/"
&lt;/FilesMatch></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF">FilesMatch </span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">php$</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    SetHandler </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost/</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;/</span><span style="color: #D8DEE9FF">FilesMatch</span><span style="color: #81A1C1">&gt;</span></span></code></pre></div>



<ul class="wp-block-list">
<li><code>SetHandler</code> indica que las peticiones PHP se deben enviar a PHP-FPM.</li>



<li>PHP-FPM escucha en un <strong>socket Unix</strong> o <strong>puerto TCP</strong> y devuelve la salida ya procesada.</li>



<li>Apache sigue manejando la conexión HTTP, logging, seguridad y otras funcionalidades, pero la ejecución de PHP queda delegada.</li>
</ul>



<h3 class="wp-block-heading">4. Resumen de diferencias</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Característica</th><th>mod_php (tradicional)</th><th>PHP-FPM (FastCGI)</th></tr></thead><tbody><tr><td>Ejecución</td><td>Dentro de Apache</td><td>Servicio externo</td></tr><tr><td>Rendimiento</td><td>Bueno en bajo tráfico</td><td>Mejor en alto tráfico</td></tr><tr><td>Memoria</td><td>Alta</td><td>Optimizada</td></tr><tr><td>Multiples versiones</td><td>Difícil</td><td>Fácil</td></tr><tr><td>Aislamiento</td><td>Bajo</td><td>Alto</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">5. Conclusión</h3>



<ul class="wp-block-list">
<li><strong>mod_php</strong> es más simple y suficiente para sitios pequeños o entornos de desarrollo.</li>



<li><strong>PHP-FPM</strong> es más eficiente, flexible y escalable, ideal para producción y sitios con alta carga.</li>



<li>Apache gestiona la parte HTTP y delega la ejecución de PHP a PHP-FPM, optimizando recursos y manteniendo la seguridad y control.</li>
</ul>



<h3 class="wp-block-heading">5. Exclusividad de PHP-FPM y orden de ejecución con Apache</h3>



<p>Cuando usamos <strong>PHP-FPM</strong>, Apache ya <strong>no ejecuta PHP directamente</strong>. Esto implica dos cosas importantes:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Nombre en paquete</th><th>Qué incluye</th></tr></thead><tbody><tr><td>php-apache</td><td>PHP + mod_php</td></tr><tr><td>php-fpm</td><td>PHP + FPM</td></tr></tbody></table></figure>



<h4 class="wp-block-heading">1&#xfe0f;&#x20e3; Exclusividad de PHP-FPM</h4>



<ul class="wp-block-list">
<li><strong>Solo puede haber un intérprete activo por socket o puerto</strong>.</li>



<li>PHP-FPM actúa como un <strong>servicio independiente</strong>, gestionando un <strong>pool de procesos</strong> que reciben solicitudes de PHP de Apache (o Nginx).</li>



<li>Si tienes múltiples instancias de PHP-FPM escuchando en el mismo socket, habrá conflictos.</li>



<li>Por eso se habla de <strong>“exclusividad”</strong>: cada pool de PHP-FPM se asigna a un <strong>sitio o versión de PHP</strong> y Apache lo llama a través del socket/puerto definido.</li>
</ul>



<h2 class="wp-block-heading">6. Ejecución del servidor</h2>



<h3 class="wp-block-heading">1&#xfe0f;&#x20e3; Arranque con <strong>mod_php (php-apache)</strong> en Alpine</h3>



<p>En Alpine, normalmente instalas el paquete <code>php-apache2</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># Instalar Apache + mod_php
apk add apache2 php8-apache2

# Iniciar Apache (que ya carga PHP internamente)
httpd -D</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #8FBCBB">Instalar</span><span style="color: #D8DEE9FF"> Apache </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> mod_php</span></span>
<span class="line"><span style="color: #D8DEE9FF">apk add apache2 php8</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">apache2</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #8FBCBB">Iniciar</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Apache</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">que ya carga </span><span style="color: #8FBCBB">PHP</span><span style="color: #D8DEE9FF"> internamente</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">httpd </span><span style="color: #81A1C1">-</span><span style="color: #8FBCBB">D</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>Nota:</strong> No hay servicio PHP externo, todo corre dentro de Apache.</li>
</ul>



<h3 class="wp-block-heading">2&#xfe0f;&#x20e3; Arranque con <strong>PHP-FPM + Apache</strong> en Alpine</h3>



<p>Instalas PHP-FPM y Apache, y configuras Apache para usar FastCGI:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># Instalar PHP-FPM y Apache
apk add php8-fpm php8-opcache apache2

# Hablitar modulo proxy o proxy_fcgi segun se necesite
...
# Agregar configuracion proxy a FCGI
...

# Iniciar FPM 
php-fpm8 

# Iniciar Apache 
httpd -D
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #8FBCBB">Instalar</span><span style="color: #D8DEE9FF"> PHP</span><span style="color: #81A1C1">-</span><span style="color: #8FBCBB">FPM</span><span style="color: #D8DEE9FF"> y </span><span style="color: #8FBCBB">Apache</span></span>
<span class="line"><span style="color: #D8DEE9FF">apk add php8</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">fpm php8</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">opcache apache2</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #8FBCBB">Hablitar</span><span style="color: #D8DEE9FF"> modulo proxy o proxy_fcgi segun se necesite</span></span>
<span class="line"><span style="color: #ECEFF4">...</span></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #8FBCBB">Agregar</span><span style="color: #D8DEE9FF"> configuracion proxy a </span><span style="color: #8FBCBB">FCGI</span></span>
<span class="line"><span style="color: #ECEFF4">...</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #8FBCBB">Iniciar</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">FPM</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">php</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">fpm8 </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF"># </span><span style="color: #8FBCBB">Iniciar</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Apache</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">httpd </span><span style="color: #81A1C1">-</span><span style="color: #8FBCBB">D</span></span>
<span class="line"></span></code></pre></div><p>The post <a href="https://randombitsonfire.com/programacion/back/php-y-php-fpm-con-apache-diferencias/">PHP y PHP-FPM con Apache: diferencias</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://randombitsonfire.com/programacion/back/php-y-php-fpm-con-apache-diferencias/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Conexiones Real Time: Server Sent Events</title>
		<link>https://randombitsonfire.com/programacion/back/conexiones-real-time-server-sent-events/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=conexiones-real-time-server-sent-events</link>
					<comments>https://randombitsonfire.com/programacion/back/conexiones-real-time-server-sent-events/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 01 Mar 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[Arquitectura]]></category>
		<category><![CDATA[Back]]></category>
		<category><![CDATA[Programacion]]></category>
		<category><![CDATA[Conexiones]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Server Sent Events]]></category>
		<category><![CDATA[Servidores]]></category>
		<guid isPermaLink="false">https://randombitsonfire.com/?p=58</guid>

					<description><![CDATA[<p>Los Server Sent Events (SSE) son una tecnología basada en HTTP que permite al servidor enviar datos al cliente de forma unidireccional y en tiempo real. A diferencia del modelo tradicional request/response, donde el cliente debe preguntar constantemente por nuevos datos (polling), con SSE el servidor mantiene la conexión abierta y envía información automáticamente cuando [&#8230;]</p>
<p>The post <a href="https://randombitsonfire.com/programacion/back/conexiones-real-time-server-sent-events/">Conexiones Real Time: Server Sent Events</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Los <strong>Server Sent Events (SSE)</strong> son una tecnología basada en HTTP que permite al servidor enviar datos al cliente de forma unidireccional y en tiempo real. A diferencia del modelo tradicional request/response, donde el cliente debe preguntar constantemente por nuevos datos (polling), con SSE el servidor mantiene la conexión abierta y envía información automáticamente cuando está disponible.</p>



<p>SSE está soportado de forma nativa por los navegadores modernos mediante la API <code>EventSource</code>, lo que lo convierte en una solución sencilla y eficiente para:</p>



<ul class="wp-block-list">
<li>Notificaciones en tiempo real</li>



<li>Actualización de dashboards</li>



<li>Logs en streaming</li>



<li>Sistemas de monitorización</li>



<li>Chats unidireccionales</li>
</ul>



<p>La comunicación se realiza sobre HTTP estándar con el tipo de contenido:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>text/event-stream</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">text</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">event</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">stream</span></span></code></pre></div>



<p>Cada evento sigue un formato simple:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>event: nombreEvento
data: contenido
id: 1</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">event</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> nombreEvento</span></span>
<span class="line"><span style="color: #D8DEE9FF">data</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> contenido</span></span>
<span class="line"><span style="color: #D8DEE9FF">id</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span></span></code></pre></div>



<h2 class="wp-block-heading">Alternativas: WebSockets</h2>



<p>La alternativa más conocida a SSE es <strong>WebSockets</strong>, una tecnología que permite comunicación bidireccional full-duplex entre cliente y servidor sobre una única conexión TCP persistente.</p>



<h3 class="wp-block-heading">Diferencias conceptuales</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th class="has-text-align-center" data-align="center">Característica</th><th class="has-text-align-center" data-align="center">SSE</th><th class="has-text-align-center" data-align="center">WebSockets</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center">Dirección</td><td class="has-text-align-center" data-align="center">Unidireccional (Servidor → Cliente)</td><td class="has-text-align-center" data-align="center">Bidireccional</td></tr><tr><td class="has-text-align-center" data-align="center">Protocolo</td><td class="has-text-align-center" data-align="center">HTTP estándar</td><td class="has-text-align-center" data-align="center">ws / wss</td></tr><tr><td class="has-text-align-center" data-align="center">Reconexión automática</td><td class="has-text-align-center" data-align="center">Sí (nativa)</td><td class="has-text-align-center" data-align="center">No (manual)</td></tr><tr><td class="has-text-align-center" data-align="center">Complejidad</td><td class="has-text-align-center" data-align="center">Baja</td><td class="has-text-align-center" data-align="center">Media/Alta</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">Tabla comparativa: Ventajas y Desventajas</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Tecnología</th><th>Ventajas</th><th>Desventajas</th></tr></thead><tbody><tr><td><strong>SSE</strong></td><td>Simple de implementar. Basado en HTTP. Reconexión automática. Ideal para notificaciones</td><td>Solo unidireccional. No soporta binarios nativamente. Limitado en algunos proxies antiguos</td></tr><tr><td><strong>WebSockets</strong></td><td>Comunicación bidireccional. Mayor flexibilidad. Soporte binario</td><td>Mayor complejidad. Gestión manual de reconexión. No siempre compatible con infraestructuras legacy.</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Implementación clásica con Spring Boot 3</h2>



<p>En Spring Boot 3, la forma tradicional de implementar SSE es mediante <code>SseEmitter</code></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;dependency>
    &lt;groupId>org.springframework.boot&lt;/groupId>
    &lt;artifactId>spring-boot-starter-web&lt;/artifactId>
&lt;/dependency></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;dependency&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;groupId&gt;</span><span style="color: #D8DEE9FF">org.springframework.boot</span><span style="color: #81A1C1">&lt;/groupId&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;artifactId&gt;</span><span style="color: #D8DEE9FF">spring-boot-starter-web</span><span style="color: #81A1C1">&lt;/artifactId&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;/dependency&gt;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>/** Service **/
public class SSEService {
        
	private Map&lt;String, SseEmitter> emitters = new ConcurrentHashMap&lt;>();
	public SseEmitter subscribe(String userId) {
        SseEmitter emitter = emitters
            .computeIfAbsent(userId, k -> new SseEmitter(0L));

        emitter.onCompletion(() -> {
        	log.info("Connection COMPLETED on USER: "+ userId);
        	remove(userId);});
        emitter.onTimeout(() -> {
        	log.info("Connection TIMEOUT on USER: "+ userId);
        	remove(userId);});
        emitter.onError(e -> {
        	log.info("Connection ERROR on USER: "+ userId);
        	remove(userId);});
        
        objs.computeIfAbsent(userId, k -> obj);

        return emitter;
    }
    public void remove(String userId) {
    	SseEmitter sse = emitters.get(userId);
        if (sse != null) {
        	log.info("CLEAN CONNECTION AND REMOVE FILTER on USER: "+ userId);
        	emitters.remove(userId);
        }
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">/** Service **/</span></span>
<span class="line"><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SSEService</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span></span>
<span class="line"><span style="color: #D8DEE9FF">	</span><span style="color: #81A1C1">private</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Map</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SseEmitter</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">emitters</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">new</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">ConcurrentHashMap</span><span style="color: #ECEFF4">&lt;&gt;()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">	</span><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SseEmitter</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">subscribe</span><span style="color: #ECEFF4">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">userId</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">SseEmitter</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">emitter</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> emitters</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">computeIfAbsent</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> k </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">new</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">SseEmitter</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">0L</span><span style="color: #ECEFF4">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">emitter</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">onCompletion</span><span style="color: #ECEFF4">(()</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #D8DEE9">log</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">info</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Connection COMPLETED on USER: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #88C0D0">remove</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #ECEFF4">})</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">emitter</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">onTimeout</span><span style="color: #ECEFF4">(()</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #D8DEE9">log</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">info</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Connection TIMEOUT on USER: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #88C0D0">remove</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #ECEFF4">})</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">emitter</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">onError</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">e </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #D8DEE9">log</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">info</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Connection ERROR on USER: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #88C0D0">remove</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #ECEFF4">})</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">objs</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">computeIfAbsent</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> k </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> obj</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> emitter</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">remove</span><span style="color: #ECEFF4">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">userId</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    	</span><span style="color: #8FBCBB">SseEmitter</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sse</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">emitters</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">sse </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #D8DEE9">log</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">info</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">CLEAN CONNECTION AND REMOVE FILTER on USER: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        	</span><span style="color: #D8DEE9">emitters</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">remove</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>/* Controller */
public class Controller {
        
	@Autowired
	private SSEService sseService;
	@GetMapping(path = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
	public SseEmitter subscribe(@RequestParam("userID") String userId) {
		log.debug("Call to SSE Subscribe");
		return service.subscribe(userId);
	}
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">/* Controller */</span></span>
<span class="line"><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Controller</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span></span>
<span class="line"><span style="color: #D8DEE9FF">	</span><span style="color: #ECEFF4">@</span><span style="color: #D08770">Autowired</span></span>
<span class="line"><span style="color: #D8DEE9FF">	</span><span style="color: #81A1C1">private</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SSEService</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sseService</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">	</span><span style="color: #ECEFF4">@</span><span style="color: #D08770">GetMapping</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">path</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/subscribe</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">produces</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MediaType</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">TEXT_EVENT_STREAM_VALUE</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">	</span><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SseEmitter</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">subscribe</span><span style="color: #ECEFF4">(@</span><span style="color: #D08770">RequestParam</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">userID</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">userId</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">		</span><span style="color: #D8DEE9">log</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">debug</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Call to SSE Subscribe</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">		</span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">service</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">subscribe</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">	</span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">Características clave</h3>



<ul class="wp-block-list">
<li>Spring mantiene la conexión abierta</li>



<li>El navegador reconecta automáticamente si se pierde</li>



<li>Se puede personalizar timeout y gestión de errores</li>
</ul>



<h1 class="wp-block-heading">Avanzado</h1>



<h2 class="wp-block-heading">Programación Reactiva</h2>



<p>En aplicaciones modernas, especialmente con alta concurrencia, el modelo bloqueante tradicional no es óptimo. Aquí entra la <strong>programación reactiva</strong>, basada en:</p>



<ul class="wp-block-list">
<li>Streams asíncronos</li>



<li>Backpressure</li>



<li>No bloqueo de hilos</li>
</ul>



<p>Spring ofrece soporte mediante <strong>Project Reactor</strong>, usando tipos como:</p>



<ul class="wp-block-list">
<li><code>Flux&lt;T&gt;</code></li>



<li><code>Mono&lt;T&gt;</code></li>
</ul>



<p>Para SSE, <code>Flux</code> es perfecto porque representa una secuencia de datos potencialmente infinita.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Uso con Spring WebFlux</h2>



<p>Para entornos altamente concurrentes o arquitecturas basadas en microservicios, WebFlux es la opción recomendada.</p>



<h3 class="wp-block-heading">Dependencia</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;dependency>
    &lt;groupId>org.springframework.boot&lt;/groupId>
    &lt;artifactId>spring-boot-starter-webflux&lt;/artifactId>
&lt;/dependency></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF">dependency</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF">groupId</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9">org</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">springframework</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">boot</span><span style="color: #81A1C1">&lt;/</span><span style="color: #D8DEE9FF">groupId</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF">artifactId</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">spring</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">boot</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">starter</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">webflux</span><span style="color: #81A1C1">&lt;/</span><span style="color: #D8DEE9FF">artifactId</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;/</span><span style="color: #D8DEE9FF">dependency</span><span style="color: #81A1C1">&gt;</span></span></code></pre></div>



<h3 class="wp-block-heading">Implementación con Flux</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>/* Service */
@Service
public class SseService {

    private final Map&lt;String, Sinks.Many&lt;String>> sinks = new ConcurrentHashMap&lt;>();

    public Sinks.Many&lt;String> createSink(String clientId) {
        return sinks.computeIfAbsent(clientId,
                id -> Sinks.many().multicast().onBackpressureBuffer());
    }

    public void publish(String clientId, String message) {
        Sinks.Many&lt;String> sink = sinks.get(clientId);
        if (sink != null) {
            sink.tryEmitNext(message);
        }
    }

    public Flux&lt;ServerSentEvent&lt;String>> subscribe(String clientId) {
        Sinks.Many&lt;String> sink = createSink(clientId);

        Flux&lt;ServerSentEvent&lt;String>> flux = sink.asFlux()
                .map(data -> ServerSentEvent.builder(data).build());

        // heartbeat to keep connections alive
        Flux&lt;ServerSentEvent&lt;String>> heartbeat = Flux.interval(Duration.ofSeconds(15))
                .map(i -> ServerSentEvent.&lt;String>builder().comment("heartbeat").build());

        return Flux.merge(flux, heartbeat)
                .doOnCancel(() -> sinks.remove(clientId));
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">/* Service */</span></span>
<span class="line"><span style="color: #ECEFF4">@</span><span style="color: #D08770">Service</span></span>
<span class="line"><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SseService</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">private</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">final</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Map</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Sinks</span><span style="color: #ECEFF4">.</span><span style="color: #8FBCBB">Many</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sinks</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">new</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">ConcurrentHashMap</span><span style="color: #ECEFF4">&lt;&gt;()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Sinks</span><span style="color: #ECEFF4">.</span><span style="color: #8FBCBB">Many</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createSink</span><span style="color: #ECEFF4">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">clientId</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sinks</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">computeIfAbsent</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">clientId</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                id </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Sinks</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">many</span><span style="color: #ECEFF4">().</span><span style="color: #88C0D0">multicast</span><span style="color: #ECEFF4">().</span><span style="color: #88C0D0">onBackpressureBuffer</span><span style="color: #ECEFF4">())</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">publish</span><span style="color: #ECEFF4">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">clientId</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">message</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">Sinks</span><span style="color: #ECEFF4">.</span><span style="color: #8FBCBB">Many</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sink</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sinks</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">clientId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">sink </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">sink</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">tryEmitNext</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">message</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Flux</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">ServerSentEvent</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">subscribe</span><span style="color: #ECEFF4">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">clientId</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">Sinks</span><span style="color: #ECEFF4">.</span><span style="color: #8FBCBB">Many</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sink</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createSink</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">clientId</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">Flux</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">ServerSentEvent</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">flux</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sink</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">asFlux</span><span style="color: #ECEFF4">()</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">map</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">data </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ServerSentEvent</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">builder</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">data</span><span style="color: #ECEFF4">).</span><span style="color: #88C0D0">build</span><span style="color: #ECEFF4">())</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// heartbeat to keep connections alive</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">Flux</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">ServerSentEvent</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">heartbeat</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Flux</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">interval</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">Duration</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">ofSeconds</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">15</span><span style="color: #ECEFF4">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">map</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">i </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> ServerSentEvent</span><span style="color: #ECEFF4">.</span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF">String</span><span style="color: #81A1C1">&gt;</span><span style="color: #88C0D0">builder</span><span style="color: #ECEFF4">().</span><span style="color: #88C0D0">comment</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">heartbeat</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">).</span><span style="color: #88C0D0">build</span><span style="color: #ECEFF4">())</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Flux</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">merge</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">flux</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> heartbeat</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">doOnCancel</span><span style="color: #ECEFF4">(()</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">-&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sinks</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">remove</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">clientId</span><span style="color: #ECEFF4">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:clamp(12px, .75rem, 18px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(16px, 1rem, 24px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>/* CONTROLLER */
@RestController
@RequestMapping("/sse")
public class SseController {
    @Autowire
    SseService sseService;

    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux&lt;ServerSentEvent&lt;String>> stream(@QueryParam String userId) {
        return sseService.subscribe(userId)
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">/* CONTROLLER */</span></span>
<span class="line"><span style="color: #ECEFF4">@</span><span style="color: #D08770">RestController</span></span>
<span class="line"><span style="color: #ECEFF4">@</span><span style="color: #D08770">RequestMapping</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/sse</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SseController</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">@</span><span style="color: #D08770">Autowire</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">SseService</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sseService</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">@</span><span style="color: #D08770">GetMapping</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">value</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/stream</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">produces</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MediaType</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">TEXT_EVENT_STREAM_VALUE</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">public</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Flux</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">ServerSentEvent</span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">&gt;&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">stream</span><span style="color: #ECEFF4">(@</span><span style="color: #D08770">QueryParam</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">userId</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sseService</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">subscribe</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">userId</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>Esto es lo que sucede:</p>



<ol class="wp-block-list">
<li>Cada cliente obtiene su propio receptor (un publicador reactivo).</li>



<li>Cuando el servidor llama a publish(clientId, message), ese mensaje se envía a todos los suscriptores.</li>



<li>Los latidos garantizan que los proxies no interrumpan la conexión.</li>



<li>Cuando un cliente se desconecta, el receptor se limpia.</li>
</ol>



<h3 class="wp-block-heading">Ventajas del enfoque reactivo</h3>



<ul class="wp-block-list">
<li>No bloquea hilos</li>



<li>Escala mejor con muchas conexiones abiertas</li>



<li>Integración natural con bases de datos reactivas</li>



<li>Soporte de backpressure</li>
</ul>



<h1 class="wp-block-heading">Conclusión</h1>



<p>Los <strong>Server-Sent Events</strong> son una solución elegante y eficiente para escenarios donde el servidor necesita enviar información en tiempo real al cliente sin requerir comunicación bidireccional.</p>



<ul class="wp-block-list">
<li>Si necesitas simplicidad → <strong>SSE clásico con Spring MVC</strong></li>



<li>Si necesitas alta concurrencia y escalabilidad → <strong>SSE con WebFlux</strong></li>



<li>Si necesitas bidireccionalidad → <strong>WebSockets</strong></li>
</ul>



<p>En arquitecturas modernas basadas en microservicios y sistemas event-driven, SSE sigue siendo una herramienta extremadamente útil, especialmente cuando se combina con programación reactiva.</p>



<h2 class="wp-block-heading">A lo mejor te interesa</h2>



<p><a href="https://www.pubnub.com/guides/http-streaming/">What is HTTP Streaming and How Does it Work?</a></p>



<p><a href="https://github.com/stomp-js/stompjs">stomp-js/stompjs: Javascript and Typescript Stomp client for Web browsers and node.js apps</a></p>



<p><a href="https://developer.mozilla.org/es/docs/Web/API/WebSockets_API">WebSockets &#8211; API web | MDN</a></p>



<p><a href="https://randombitsonfire.com/arquitectura/stack-para-testing-swarm-jmeter/" title="Stack para Testing (Swarm+ jMeter)">Stack para Testing (Swarm + jMeter)</a></p>



<p><a href="https://medium.com/@chillBroh/real-time-applications-with-server-sent-events-sse-in-spring-boot-186cdeffb42f">Real-Time Applications with Server-Sent Events (SSE) in Spring Boot | by Ishara Madusanka | Medium</a></p><p>The post <a href="https://randombitsonfire.com/programacion/back/conexiones-real-time-server-sent-events/">Conexiones Real Time: Server Sent Events</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://randombitsonfire.com/programacion/back/conexiones-real-time-server-sent-events/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Stack para Testing (Swarm+ jMeter)</title>
		<link>https://randombitsonfire.com/arquitectura/stack-para-testing-swarm-jmeter/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=stack-para-testing-swarm-jmeter</link>
					<comments>https://randombitsonfire.com/arquitectura/stack-para-testing-swarm-jmeter/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 20 Feb 2026 01:54:32 +0000</pubDate>
				<category><![CDATA[Arquitectura]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[jMeter]]></category>
		<category><![CDATA[Swarm]]></category>
		<guid isPermaLink="false">https://randombitsonfire.com/?p=128</guid>

					<description><![CDATA[<p>Introducción Es común que cuando se diseña una arquitectura de aplicaciones no baste con el desarrollo de Tests Unitarios o Tests de Integraciones, y se pase a un nivel superior, llamando se así Pruebas de Rendimiento (Performance Testing). Pruebas de rendimiento Las Pruebas de Rendimiento son una técnica de testing que consiste en someter un [&#8230;]</p>
<p>The post <a href="https://randombitsonfire.com/arquitectura/stack-para-testing-swarm-jmeter/">Stack para Testing (Swarm+ jMeter)</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Introducción</h2>



<p>Es común que cuando se diseña una arquitectura de aplicaciones no baste con el desarrollo de Tests Unitarios o Tests de Integraciones, y se pase a un nivel superior, llamando se así <strong>Pruebas de Rendimiento</strong> (Performance Testing). </p>



<h3 class="wp-block-heading">Pruebas de rendimiento</h3>



<p>Las <strong>Pruebas de Rendimiento</strong> son una técnica de testing que consiste en someter un sistema a un volumen de peticiones controlado para analizar cómo se comporta bajo condiciones reales o esperadas de uso.</p>



<p>No se trata solo de “ver si aguanta”, sino de entender:</p>



<ul class="wp-block-list">
<li>Cuándo empieza a degradarse el rendimiento</li>



<li>Cómo responde el sistema cuando crece el tráfico</li>



<li>Dónde están los cuellos de botella</li>
</ul>



<p>Suelen a tender a las siguientes modalidades en base a la pregunta que se quiere contestar:</p>



<ul class="wp-block-list">
<li><strong>Load testing</strong> → tráfico esperado normal</li>



<li><strong>Stress testing</strong> → llevar el sistema al límite</li>



<li><strong>Spike testing</strong> → picos bruscos de tráfico</li>



<li><strong>Soak testing</strong> → carga sostenida durante mucho tiempo</li>
</ul>



<h3 class="wp-block-heading">Optimización tras las pruebas</h3>



<p>Una vez identificados los límites, el siguiente paso consiste en aplicar mejoras. Entre las más habituales encontramos:</p>



<ul class="wp-block-list">
<li>Aumento de memoria o CPU</li>



<li>Ajustes de configuración (fine tuning)</li>



<li>Pools de conexiones</li>



<li>Pools de threads</li>
</ul>



<p>En consecuencia, estas optimizaciones permiten escalar el sistema de forma controlada y eficiente.</p>



<h2 class="wp-block-heading">Testing Tools</h2>



<p>Un entorno de pruebas controlado no es un lujo, es una necesidad.</p>



<p>La combinación de:</p>



<ul class="wp-block-list">
<li><a href="https://docs.docker.com/engine/swarm/" title="Docker Swarm">Docker Swarm</a> (orquestación): Permite tener varias instancias de un contenedor y ver como se comporta en casos de balanceos</li>



<li><a href="https://prometheus.io/" title="">Prometheus </a>(métricas)</li>



<li><a href="https://grafana.com/" title="">Grafana </a>(visualización)</li>



<li><a href="https://spring.io/projects/spring-boot" title="">Spring Boot</a> + <a href="https://micrometer.io/" title="">Micrometer </a>(instrumentación)</li>



<li><a href="https://jmeter.apache.org/" title="">jMeter</a></li>
</ul>



<p>De este modo, se obtiene un ecosistema completo de observabilidad en local, muy cercano a producción y completamente reproducible.</p>



<p>Esto se traduce en <strong>menos errores, despliegues más seguros y sistemas más robustos</strong>.</p>



<p>Para ello encontré el siguiente stack que me vino de lujo para la monitorización de los diferentes micros, para ejecutar en entornos locales de prueba (y un buen maquinón xD):</p>



<p><a href="https://github.com/stefanprodan/swarmprom">https://github.com/stefanprodan/swarmprom</a></p>



<p><a href="https://dockerswarm.rocks/swarmprom">https://dockerswarm.rocks/swarmprom</a></p>



<p>Este stack integra Prometheus, Grafana y múltiples exporters listos para usar.</p>



<p>No obstante, en mi caso decidí simplificarlo ligeramente, eliminando componentes como el alerting o la integración con Slack, ya que no eran necesarios en un entorno local.</p>



<p>También quité Treffic y utilice accesos directo por localhost y sus respectivas apertura de puertos.</p>



<h2 class="wp-block-heading">jMeter</h2>



<p>Por otro lado, la generación de carga es una pieza clave. Para ello, utilicé Apache JMeter, una herramienta ampliamente utilizada en pruebas de rendimiento.</p>



<p>Sin embargo, jMeter suele venir bastante limitado de serie. Por esta razón, es recomendable ampliar sus capacidades mediante plugins.</p>



<p>En particular, una colección muy útil incluye:</p>



<ul class="wp-block-list">
<li>3 Basic Graphs</li>



<li>5 Additional Graphs</li>



<li>Composite Timeline Graph</li>



<li>Custom Thread Groups</li>



<li>Parallel Controller &amp; Sampler</li>
</ul>



<p>Gracias a estos plugins, es posible obtener una visión mucho más completa del comportamiento del sistema.</p>



<h2 class="wp-block-heading">Resultados de Testing</h2>



<p>Finalmente, el resultado es un conjunto de métricas y estadísticas que, aunque mejorables, ofrecen una base sólida para analizar la robustez de la solución planteada.</p>



<p>A partir de aquí, además, se pueden empezar a explotar métricas clave, detectar patrones de comportamiento y tomar decisiones informadas para mejorar el sistema.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="512" height="205" data-id="132" src="https://randombitsonfire.com/wp-content/uploads/2026/02/theeshold.png" alt="testing Custom Thread Groups" class="wp-image-132" srcset="https://randombitsonfire.com/wp-content/uploads/2026/02/theeshold.png 512w, https://randombitsonfire.com/wp-content/uploads/2026/02/theeshold-300x120.png 300w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="512" height="198" data-id="134" src="https://randombitsonfire.com/wp-content/uploads/2026/02/responseTimes.png" alt="testing 5 Additional Graphs" class="wp-image-134" srcset="https://randombitsonfire.com/wp-content/uploads/2026/02/responseTimes.png 512w, https://randombitsonfire.com/wp-content/uploads/2026/02/responseTimes-300x116.png 300w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="512" height="187" data-id="133" src="https://randombitsonfire.com/wp-content/uploads/2026/02/httpcodes.png" alt="testing 5 Additional Graphs" class="wp-image-133" srcset="https://randombitsonfire.com/wp-content/uploads/2026/02/httpcodes.png 512w, https://randombitsonfire.com/wp-content/uploads/2026/02/httpcodes-300x110.png 300w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="512" height="79" data-id="136" src="https://randombitsonfire.com/wp-content/uploads/2026/02/cpu.png" alt="Testing grafana CPU Service" class="wp-image-136" srcset="https://randombitsonfire.com/wp-content/uploads/2026/02/cpu.png 512w, https://randombitsonfire.com/wp-content/uploads/2026/02/cpu-300x46.png 300w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="512" height="102" data-id="135" src="https://randombitsonfire.com/wp-content/uploads/2026/02/mem.png" alt="Testing grafana Memory Service" class="wp-image-135" srcset="https://randombitsonfire.com/wp-content/uploads/2026/02/mem.png 512w, https://randombitsonfire.com/wp-content/uploads/2026/02/mem-300x60.png 300w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>
</figure>



<p class="has-text-align-right">Saludos and Happy Codding!!</p>



<p></p><p>The post <a href="https://randombitsonfire.com/arquitectura/stack-para-testing-swarm-jmeter/">Stack para Testing (Swarm+ jMeter)</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://randombitsonfire.com/arquitectura/stack-para-testing-swarm-jmeter/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Dedicar el tiempo en tareas más productivas</title>
		<link>https://randombitsonfire.com/general/dedicar-el-tiempo-en-tareas-mas-productivas/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dedicar-el-tiempo-en-tareas-mas-productivas</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 08 Feb 2026 17:04:45 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Delivery]]></category>
		<category><![CDATA[Organizacion]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://randombitsonfire.com/?p=60</guid>

					<description><![CDATA[<p>Bienvenidos al nuevo espacio de RBOF. Moderno, renovado y con un diseño diferente. Así invertimos mejor el tiempo. Tras muchos años adoptando nuestra propia imagen con una web con ángular y Springboot finalmente sucumbimos al &#8220;todo poderoso&#8221; PHP. El tiempo, y no hablando en términos de rendimiento, es limitado, pasa y no vuelve y uno [&#8230;]</p>
<p>The post <a href="https://randombitsonfire.com/general/dedicar-el-tiempo-en-tareas-mas-productivas/">Dedicar el tiempo en tareas más productivas</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Bienvenidos al nuevo espacio de RBOF. Moderno, renovado y con un diseño diferente. Así invertimos mejor el tiempo.</p>



<p>Tras muchos años adoptando nuestra propia imagen con una web con ángular y Springboot finalmente sucumbimos al &#8220;todo poderoso&#8221; <a href="https://www.php.net/" title="">PHP</a>. El tiempo, y no hablando en términos de rendimiento, es limitado, pasa y no vuelve y uno ha de decidir cómo y en qué invertirlo. Muchos de los proyectos que llevo son ambiciosos y requieren pruebas para que exista un correcto funcionamiento. La informática, como todo proceso científico, parte de hipótesis para la construcción de proyectos (en muchos casos controlas más en otros meno el problema, la tecnología o la implantación).</p>



<p>La I+D+I es hipótesis error constante, hasta encontrar nuevos focos y puntos de vista para resolver situaciones de maneras mas eficaces. También conlleva tiempo y esfuerzo en realizar las tareas y ser asertivo con los errores y las dificultades, aunque no estaríamos aquí si no fuera por la superación de nosotros mismos y la resolución de las metas que nos proponemos.</p>



<p>Es por ello que como decíamos el tiempo es decisivo y por lo que se ha de decidir como invertirlo. La antigua RBOF fue levantada con ilusiones pensando que pudiese ser la solución definitiva donde poder reflejar nuestras habilidades, pero los proyectos crecen, se vuelven complicados y sus frutos mejoran el sabor con el tiempo, teniendo que dejar unos para avanzar otros, que también vemos como triunfos de nuestro trabajo.</p>



<p>Finalmente, nuestro ecosistema de Micros se verá mermado por la falta de tiempo aplicando soluciones PHP robusta del mercado, de código abierto y que nos ayudarán a, como decían en un anterior trabajo que tuve:</p>



<p>&#8211; &#8220;Dedicar el tiempo en tareas más productivas&#8221;</p>



<p class="has-text-align-right">Un saludo,<br>PaCHoN</p>



<p></p><p>The post <a href="https://randombitsonfire.com/general/dedicar-el-tiempo-en-tareas-mas-productivas/">Dedicar el tiempo en tareas más productivas</a> first appeared on <a href="https://randombitsonfire.com">RandomBitsOnFire</a>.</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
