package com.ankurm.ssews; import java.time.Instant; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.apache.tomcat.util.threads.ThreadPoolExecutor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.boot.tomcat.TomcatWebServer; import org.springframework.boot.web.server.context.WebServerApplicationContext; import static org.assertj.core.api.Assertions.assertThat; /** * Forty open SSE streams on a ten-thread Tomcat. * *
This is the test that answers the objection people raise first — "doesn't SSE pin a * thread per client?" It does not. {@code SseEmitter} puts the request into asynchronous mode, * the request thread returns to the pool, and the response stays open with no thread attached to * it. Forty concurrent streams on a pool of ten is the cheapest way to show that; the same test * with a blocking handler deadlocks at the eleventh client. * *
What SSE does cost is a socket per stream, plus one serialise-and-write per stream
* per broadcast, both of which the transcript makes visible.
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {"dashboard.broadcast.enabled=false", "server.tomcat.threads.max=10"})
class SseConcurrencyTest {
private static final int CLIENTS = 40;
@LocalServerPort
int port;
@Autowired
EmitterRegistry registry;
@Autowired
WebServerApplicationContext context;
@Test
void fortyStreamsOnTenThreads() throws Exception {
List