Hi, Yes. my bad. I just remove the commit.
Arturo On Tue, Dec 23, 2025 at 10:40 AM Oleg Kalnichevski <[email protected]> wrote: > Why are those changes in the 5.6 and not in 5.7? SSE module in is master > and is not in the 5.6.x branch. > > Oleg > > > https://github.com/apache/httpcomponents-website/tree/master/src/site/markdown/httpcomponents-client-5.7.x > > On 12/23/2025 10:10, [email protected] wrote: > > This is an automated email from the ASF dual-hosted git repository. > > > > abernal pushed a commit to branch master > > in repository > https://gitbox.apache.org/repos/asf/httpcomponents-website.git > > > > > > The following commit(s) were added to refs/heads/master by this push: > > new bb99baa Add HttpClient SSE module docs (overview, guide, > examples, javadocs links) > > bb99baa is described below > > > > commit bb99baa372e97666bb4624452afef77cba20f8fa > > Author: Arturo Bernal <[email protected]> > > AuthorDate: Tue Dec 23 10:10:10 2025 +0100 > > > > Add HttpClient SSE module docs (overview, guide, examples, javadocs > links) > > --- > > .../httpcomponents-client-5.6.x/examples-sse.md | 191 > ++++++++++++++++++++ > > .../markdown/httpcomponents-client-5.6.x/index.md | 6 + > > .../markdown/httpcomponents-client-5.6.x/sse.md | 192 > +++++++++++++++++++++ > > 3 files changed, 389 insertions(+) > > > > diff --git > a/src/site/markdown/httpcomponents-client-5.6.x/examples-sse.md > b/src/site/markdown/httpcomponents-client-5.6.x/examples-sse.md > > new file mode 100644 > > index 0000000..6977ca6 > > --- /dev/null > > +++ b/src/site/markdown/httpcomponents-client-5.6.x/examples-sse.md > > @@ -0,0 +1,191 @@ > > +<!-- > > + Licensed to the Apache Software Foundation (ASF) under one > > + or more contributor license agreements. See the NOTICE file > > + distributed with this work for additional information > > + regarding copyright ownership. The ASF licenses this file > > + to you under the Apache License, Version 2.0 (the > > + "License"); you may not use this file except in compliance > > + with the License. You may obtain a copy of the License at > > + > > + http://www.apache.org/licenses/LICENSE-2.0 > > + > > + Unless required by applicable law or agreed to in writing, > > + software distributed under the License is distributed on an > > + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > > + KIND, either express or implied. See the License for the > > + specific language governing permissions and limitations > > + under the License. > > +--> > > + > > +HttpClient SSE examples > > +======================= > > + > > +This page shows complete examples for the optional SSE module > (`httpclient5-sse`). > > + > > +Example 1: public stream (Wikimedia recent changes) > > +--------------------------------------------------- > > + > > +This example is based on > `org.apache.hc.client5.http.sse.example.ClientSseExample` from the > > +`httpclient5-sse` module tests. > > + > > +It demonstrates: > > + > > +- Custom async client with HTTP/2 negotiation and stream multiplexing. > > +- Dedicated scheduler for reconnect backoff. > > +- `SseParser.BYTE` for reduced allocations. > > +- A simple listener with lifecycle handling. > > + > > +```java > > +import java.net.URI; > > +import java.util.HashMap; > > +import java.util.Locale; > > +import java.util.Map; > > +import java.util.concurrent.CountDownLatch; > > +import java.util.concurrent.Executor; > > +import java.util.concurrent.ScheduledThreadPoolExecutor; > > + > > +import org.apache.hc.client5.http.config.TlsConfig; > > +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; > > +import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; > > +import > org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; > > +import > org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; > > +import org.apache.hc.client5.http.sse.EventSource; > > +import org.apache.hc.client5.http.sse.EventSourceConfig; > > +import org.apache.hc.client5.http.sse.EventSourceListener; > > +import org.apache.hc.client5.http.sse.SseExecutor; > > +import org.apache.hc.client5.http.sse.impl.ExponentialJitterBackoff; > > +import org.apache.hc.client5.http.sse.impl.SseParser; > > +import org.apache.hc.core5.concurrent.DefaultThreadFactory; > > +import org.apache.hc.core5.http2.HttpVersionPolicy; > > +import org.apache.hc.core5.http2.config.H2Config; > > +import org.apache.hc.core5.reactor.IOReactorConfig; > > +import org.apache.hc.core5.util.TimeValue; > > + > > +public final class ClientSseExample { > > + > > + public static void main(final String[] args) throws Exception { > > + final URI uri = URI.create(args.length > 0 > > + ? args[0] > > + : "https://stream.wikimedia.org/v2/stream/recentchange > "); > > + > > + final IOReactorConfig ioCfg = IOReactorConfig.custom() > > + .setIoThreadCount(Math.max(2, > Runtime.getRuntime().availableProcessors())) > > + .setSoKeepAlive(true) > > + .setTcpNoDelay(true) > > + .build(); > > + > > + final PoolingAsyncClientConnectionManager connMgr = > > + PoolingAsyncClientConnectionManagerBuilder.create() > > + .useSystemProperties() > > + .setMessageMultiplexing(true) > > + .setMaxConnPerRoute(32) > > + .setMaxConnTotal(256) > > + .setDefaultTlsConfig( > > + TlsConfig.custom() > > + > .setVersionPolicy(HttpVersionPolicy.NEGOTIATE) > > + .build()) > > + .build(); > > + > > + final CloseableHttpAsyncClient httpClient = > HttpAsyncClientBuilder.create() > > + .setIOReactorConfig(ioCfg) > > + .setConnectionManager(connMgr) > > + .setH2Config(H2Config.custom() > > + .setPushEnabled(false) > > + .setMaxConcurrentStreams(256) > > + .build()) > > + .useSystemProperties() > > + .evictExpiredConnections() > > + .evictIdleConnections(TimeValue.ofMinutes(1)) > > + .build(); > > + > > + final ScheduledThreadPoolExecutor scheduler = > > + new ScheduledThreadPoolExecutor(4, new > DefaultThreadFactory("sse-backoff", true)); > > + scheduler.setRemoveOnCancelPolicy(true); > > + > > + final Executor callbacks = Runnable::run; > > + > > + final EventSourceConfig cfg = EventSourceConfig.builder() > > + .backoff(new ExponentialJitterBackoff(500L, 30_000L, > 2.0, 250L)) > > + .maxReconnects(-1) > > + .build(); > > + > > + final Map<String, String> defaultHeaders = new HashMap<>(); > > + defaultHeaders.put("User-Agent", "Apache-HttpClient-SSE/5.x"); > > + defaultHeaders.put("Accept-Language", "en"); > > + > > + final SseExecutor exec = SseExecutor.custom() > > + .setHttpClient(httpClient) > > + .setScheduler(scheduler) > > + .setCallbackExecutor(callbacks) > > + .setEventSourceConfig(cfg) > > + .setDefaultHeaders(defaultHeaders) > > + .setParserStrategy(SseParser.BYTE) > > + .build(); > > + > > + final CountDownLatch done = new CountDownLatch(1); > > + > > + final EventSourceListener listener = new EventSourceListener() { > > + @Override > > + public void onOpen() { > > + System.out.println("[SSE] open: " + uri); > > + } > > + > > + @Override > > + public void onEvent(final String id, final String type, > final String data) { > > + final String shortData = data.length() > 120 ? > data.substring(0, 120) + "…" : data; > > + System.out.printf(Locale.ROOT, "[SSE] %s id=%s %s%n", > > + type != null ? type : "message", id, shortData); > > + } > > + > > + @Override > > + public void onFailure(final Throwable t, final boolean > willReconnect) { > > + System.err.println("[SSE] failure: " + t + " > willReconnect=" + willReconnect); > > + if (!willReconnect) { > > + done.countDown(); > > + } > > + } > > + > > + @Override > > + public void onClosed() { > > + System.out.println("[SSE] closed"); > > + done.countDown(); > > + } > > + }; > > + > > + final EventSource es = exec.open(uri, listener); > > + > > + Runtime.getRuntime().addShutdownHook(new Thread(() -> { > > + try { > > + es.cancel(); > > + } catch (final Exception ignore) { > > + } > > + try { > > + exec.close(); > > + } catch (final Exception ignore) { > > + } > > + try { > > + scheduler.shutdownNow(); > > + } catch (final Exception ignore) { > > + } > > + }, "sse-shutdown")); > > + > > + es.start(); > > + done.await(); > > + > > + es.cancel(); > > + exec.close(); > > + scheduler.shutdownNow(); > > + } > > +} > > +``` > > + > > +Example 2: perf harness > > +---------------------- > > + > > +The `httpclient5-sse` tests also include a small performance harness: > > + > > +- `org.apache.hc.client5.http.sse.example.performance.SsePerfServer` – > local SSE server with configurable rate/payload. > > +- `org.apache.hc.client5.http.sse.example.performance.SsePerfClient` – > many connections, ramp-up batching, simple > > + latency histogram. > > + > > +Those classes are intended for development / benchmarking (not as a > public API). > > diff --git a/src/site/markdown/httpcomponents-client-5.6.x/index.md > b/src/site/markdown/httpcomponents-client-5.6.x/index.md > > index dd05275..311d5e1 100644 > > --- a/src/site/markdown/httpcomponents-client-5.6.x/index.md > > +++ b/src/site/markdown/httpcomponents-client-5.6.x/index.md > > @@ -53,6 +53,8 @@ Documentation > > * [Observation](observation.md) > > * [SCRAM-SHA-256](scram-sha-256.md) > > * [SPKI pinning TLS strategy](spki-pinning.md) > > + * [Server-Sent Events (SSE)](sse.md) > > + > > > > 6. Examples demonstrating some common as well as more complex use cases > > > > @@ -60,6 +62,7 @@ Documentation > > * [HttpClient (async APIs)](examples-async.md) > > * [HttpClient (reactive APIs)](examples-reactive.md) > > * [HttpClient (observation APIs)](examples-observation.md) > > + * [HttpClient (SSE APIs)](examples-sse.md) > > > > 1. Javadocs > > > > @@ -67,6 +70,7 @@ Documentation > > * [HC Fluent](./current/httpclient5-fluent/apidocs/) > > * [HttpClient Cache](./current/httpclient5-cache/apidocs/) > > * [HttpClient > Observation](./current/httpclient5-observation/apidocs/) > > + * [HttpClient SSE](./current/httpclient5-sse/apidocs/) > > > > 1. API compatibility reports > > > > @@ -99,6 +103,8 @@ Features > > - Optional Server-Sent Events (SSE) module for consuming long-lived > event > > streams over HTTP/1.1 and HTTP/2 using the async transport. > > - Source code is freely available under the Apache License. > > +- Optional Server-Sent Events (SSE) module for consuming long-lived > event > > + streams over HTTP/1.1 and HTTP/2 using the async transport. > > > > > > Standards Compliance > > diff --git a/src/site/markdown/httpcomponents-client-5.6.x/sse.md > b/src/site/markdown/httpcomponents-client-5.6.x/sse.md > > new file mode 100644 > > index 0000000..748770d > > --- /dev/null > > +++ b/src/site/markdown/httpcomponents-client-5.6.x/sse.md > > @@ -0,0 +1,192 @@ > > +<!-- > > + Licensed to the Apache Software Foundation (ASF) under one > > + or more contributor license agreements. See the NOTICE file > > + distributed with this work for additional information > > + regarding copyright ownership. The ASF licenses this file > > + to you under the Apache License, Version 2.0 (the > > + "License"); you may not use this file except in compliance > > + with the License. You may obtain a copy of the License at > > + > > + http://www.apache.org/licenses/LICENSE-2.0 > > + > > + Unless required by applicable law or agreed to in writing, > > + software distributed under the License is distributed on an > > + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > > + KIND, either express or implied. See the License for the > > + specific language governing permissions and limitations > > + under the License. > > +--> > > + > > +Server-Sent Events (SSE) > > +======================== > > + > > +Server-Sent Events (SSE) is a simple, server → client streaming > protocol built on top of HTTP. The server keeps an > > +HTTP response open and sends events as lines in the `text/event-stream` > format. > > + > > +HttpClient provides an optional SSE module (`httpclient5-sse`) that > consumes long-lived event streams over HTTP/1.1 and > > +HTTP/2 using the async transport. > > + > > +Requirements > > +------------ > > + > > +- Java 8+ > > +- Apache HttpClient 5.7+ (the SSE module is `@since 5.7`) > > + > > +Dependency > > +---------- > > + > > +Maven: > > + > > +```xml > > +<dependency> > > + <groupId>org.apache.httpcomponents.client5</groupId> > > + <artifactId>httpclient5-sse</artifactId> > > + <version>${httpclient.version}</version> > > +</dependency> > > +``` > > + > > +Gradle: > > + > > +```gradle > > > +implementation("org.apache.httpcomponents.client5:httpclient5-sse:${httpclientVersion}") > > +``` > > + > > +Quick start > > +----------- > > + > > +The SSE API is intentionally small: > > + > > +- `SseExecutor` is the entry point. > > +- `EventSource` represents a single SSE stream. > > +- `EventSourceListener` receives events and lifecycle callbacks. > > + > > +Minimal example (shared async client): > > + > > +```java > > +import java.net.URI; > > + > > +import org.apache.hc.client5.http.sse.EventSource; > > +import org.apache.hc.client5.http.sse.EventSourceListener; > > +import org.apache.hc.client5.http.sse.SseExecutor; > > + > > +public final class MinimalSse { > > + > > + public static void main(final String[] args) throws Exception { > > + final URI uri = URI.create(" > https://stream.wikimedia.org/v2/stream/recentchange"); > > + > > + final SseExecutor exec = SseExecutor.newInstance(); > > + final EventSource es = exec.open(uri, new EventSourceListener() > { > > + @Override > > + public void onOpen() { > > + System.out.println("[SSE] open"); > > + } > > + > > + @Override > > + public void onEvent(final String id, final String type, > final String data) { > > + System.out.println("[SSE] " + (type != null ? type : > "message") + ": " + data); > > + } > > + > > + @Override > > + public void onFailure(final Throwable t, final boolean > willReconnect) { > > + System.err.println("[SSE] failure=" + t + " > willReconnect=" + willReconnect); > > + } > > + > > + @Override > > + public void onClosed() { > > + System.out.println("[SSE] closed"); > > + } > > + }); > > + > > + es.start(); > > + > > + // ... do other work ... > > + > > + // Stop the stream (no further reconnects) when you are done. > > + es.cancel(); > > + > > + // When using the shared client, exec.close() is a no-op. > > + // Call SseExecutor.closeSharedClient() if you want to > explicitly shut it down. > > + } > > +} > > +``` > > + > > +Configuration > > +------------- > > + > > +Reconnect / backoff > > +~~~~~~~~~~~~~~~~~~~ > > + > > +Reconnects are controlled by `EventSourceConfig` and `BackoffStrategy`. > > + > > +- `maxReconnects = -1` means “try forever”. > > +- The default backoff is `ExponentialJitterBackoff` and it honors > server hints: > > + - the SSE `retry:` field (milliseconds) > > + - the HTTP `Retry-After` header > > + > > +Example: > > + > > +```java > > +import org.apache.hc.client5.http.sse.EventSourceConfig; > > +import org.apache.hc.client5.http.sse.impl.ExponentialJitterBackoff; > > + > > +final EventSourceConfig cfg = EventSourceConfig.builder() > > + .backoff(new ExponentialJitterBackoff(500L, 30_000L, 2.0, 250L)) > > + .maxReconnects(-1) > > + .build(); > > +``` > > + > > +Threading > > +~~~~~~~~~ > > + > > +Listener callbacks must be non-blocking. > > + > > +- If you do heavy work in `onEvent(...)`, provide a callback executor > so the I/O threads stay responsive. > > +- Reconnect scheduling can use an application scheduler (recommended > for large fan-out). > > + > > +The builder makes those defaults explicit: > > + > > +```java > > +import java.util.concurrent.Executor; > > +import java.util.concurrent.ScheduledExecutorService; > > + > > +import org.apache.hc.client5.http.sse.SseExecutor; > > + > > +final ScheduledExecutorService scheduler = /* your scheduler */; > > +final Executor callbacks = /* your callback executor */; > > + > > +final SseExecutor exec = SseExecutor.custom() > > + .setScheduler(scheduler) > > + .setCallbackExecutor(callbacks) > > + .build(); > > +``` > > + > > +HTTP/2 multiplexing > > +~~~~~~~~~~~~~~~~~~~ > > + > > +SSE works over HTTP/1.1 and HTTP/2. > > + > > +- The default shared client created by `SseExecutor.newInstance()` uses > a pooling async connection manager with message > > + multiplexing enabled. > > +- If you provide your own async client, enable message multiplexing if > you plan to run many streams over a small number > > + of HTTP/2 connections. > > + > > +Request headers and resumption > > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > + > > +- The implementation always sends `Accept: text/event-stream`. > > +- The most recent non-null event id is tracked and used as > `Last-Event-ID` on reconnect. > > +- You can set and remove headers on the `EventSource` to affect > subsequent reconnects. > > + > > +```java > > +es.setHeader("Authorization", "Bearer ..."); > > +es.removeHeader("Authorization"); > > + > > +final String last = es.lastEventId(); > > +es.setLastEventId(last); // override / resume manually > > +``` > > + > > +See also > > +-------- > > + > > +- [SSE examples](examples-sse.md) > > +- Module javadocs: `./current/httpclient5-sse/apidocs/` > > > >
