# Ignition 8.1 Jetty 12 Upgrade

**URL:** <https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482>\
**Category:** Ignition Early Access\
**Created:** [April 23, 2025, 7:51pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482 "2025-04-23T19:51:58Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![jspecht](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jspecht/32/6465_2.png) [@jspecht](https://forum.inductiveautomation.com/u/jspecht)\
**Post date:** [April 23, 2025, 7:51pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/1 "2025-04-23T19:51:58Z")

</div>

Tomorrow's (4-24-2025) 8.1.49-SNAPSHOT early access build includes a major upgrade of [Jetty](https://jetty.org/) - the third party library Ignition depends on for powering the Gateway's embedded web server.

The primary reason for the major upgrade is: [Jetty v10 is end of life](https://github.com/jetty/jetty.project/issues/10485) and will no longer receive critical bug fixes and security patches. This is at odds with our commitment for long term support of Ignition 8.1.

Performing a major upgrade of a core dependency such as Jetty is a major undertaking and not without risk. However, our development and QA team has already performed the upgrade early on in our 8.3 branch successfully, and we have learned many lessons from that effort which have been applied successfully in 8.1. We have also undergone a rigorous QA testing cycle in 8.1 to root out any issues early on before we were confident with the change.

Ideally, on upgrade to 8.1.49, you should notice no difference with this upgrade. Module authors should also notice no Ignition API changes, unless you also depend on Jetty APIs, in which case you will want to bump your module's Jetty dependency to v12.0.17.

Because this is such a major upgrade on a minor LTS version upgrade of Ignition, out of an abundance of caution, I am posting this message to encourage folks to try out the 8.1.49 Early Access build for yourselves. If you are a module author, make sure your module is compatible with the upgrade. Please post issues here if you notice anything.

My hope is that with our rigorous internal testing efforts and with an early warning in this forum to give folks plenty of time to raise red flags with this upgrade, by the time the final build of 8.1.49 is published, we can all be confident that Ignition's web server is up-to-date and secure for the LTS years ahead of us.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [April 23, 2025, 7:57pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/2 "2025-04-23T19:57:38Z")

</div>

Will test. If my v8.3 conversions are a guide, I will have to offer v8.1.49+ module files for my Blob Server and my Image Streamer. (Both register servlets, and that requires the v10 APIs that were moved in v12.)

---

<div class="post-metadata">

**Author:** ![jspecht](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jspecht/32/6465_2.png) [@jspecht](https://forum.inductiveautomation.com/u/jspecht)\
**Post date:** [April 23, 2025, 8:01pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/3 "2025-04-23T20:01:56Z")

</div>

Thanks Phil. I'll note: in 8.1, we bumped the servlet spec from v3.1.0 to v4.0.1, but that should not cause a breaking API change, because we kept on the `javax.servlet.*` package, whereas in 8.3, we upgraded the servlet spec to v6.0.0 and also moved from the `jaxax.servlet.*` package to the `jakarta.servlet.*` package, which was a breaking API change in 8.3. This is important because the servlet API bleeds into the Ignition public API, whereas Jetty APIs are an implementation detail that does not bleed into Ignition's public APIs.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [April 23, 2025, 8:06pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/4 "2025-04-23T20:06:35Z")

</div>

The location of the servlet package didn't trouble me. It was gaining access to the output stream to efficiently deliver big results that led to the moved Jetty API. I haven't figured out Jetty v12's handler architecture yet.

---

<div class="post-metadata">

**Author:** ![jspecht](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jspecht/32/6465_2.png) [@jspecht](https://forum.inductiveautomation.com/u/jspecht)\
**Post date:** [April 23, 2025, 9:25pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/5 "2025-04-23T21:25:10Z")

</div>

In your case, does the `HttpServletResponse`'s output stream not work?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [April 23, 2025, 10:43pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/6 "2025-04-23T22:43:48Z")

</div>

Thanks for the update, this does impact my Server Sent Events module.

Embr currently targets 8.1.33, but I will eventually change to target whatever becomes 8.1's final(ish) release.

I might just let the SSE module remain broken until then, unless someone complains 🤷‍♂️ My larger plans for the module entirely revolve around Event Streams, so support of the 8.1 version is not a priority.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [April 24, 2025, 1:48am UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/7 "2025-04-24T01:48:05Z")

</div>

> [@jspecht](#):
>
> does the `HttpServletResponse`'s output stream not work?

Ah, it won't be an issue for the Blob Server, after all, because it fires the one payload and done.

I do more in the Image Streamer to detect "closed", which the jetty api offers in the HttpOutputStream.

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [May 16, 2025, 12:53pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/8 "2025-05-16T12:53:53Z")

</div>

Hello, in a module with websockets managed by Ignition Jetty werserver, we are using the following artifact:

```python
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>10.0.15</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-jetty-api</artifactId>
            <version>10.0.15</version>
            <scope>provided</scope>
        </dependency>
		
        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-jetty-server</artifactId>
            <version>10.0.15</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-servlet</artifactId>
            <version>10.0.15</version>
            <scope>provided</scope>
        </dependency>

```

I try to upgrade them for Ignition **8.1.49** ,

it works for:

```python
        <!-- Core Jetty server -->
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>12.0.17</version>
            <scope>provided</scope>
        </dependency>

```

but not with:

```python
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>12.0.17</version>
        </dependency>
        
        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-jetty-api</artifactId>
            <version>12.0.17</version>
            <scope>provided</scope>
        </dependency>
        
        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-jetty-server</artifactId>
            <version>12.0.17</version>
            <scope>provided</scope>
        </dependency>

```

```python
Could not find artifact org.eclipse.jetty:jetty-servlet:pom:12.0.17 in releases (https://nexus.inductiveautomation.com/repository/inductiveautomation-releases)

```

I'm not sure I have selected the right new articfact ?

**My code with Jetty 10:**

```python
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;

import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest;
import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse;
import org.eclipse.jetty.websocket.server.JettyWebSocketCreator;

import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;

....

    public void createServer(int maxClient) {
        try {
            this.maxClient = maxClient;
            WebResourceManager web = gatewayContext.getWebResourceManager();
            web.addServlet(wsPath, PerspectiveWebSocketServlet.class);
            logger.info("createServer : {} servlet added",wsPath);
            this.executorProcessReception = Executors.newFixedThreadPool(maxClient);
        } catch (Exception e) {
            logger.error("createServer : Exception : ", e);
        }
    }

...

    public static class PerspectiveWebSocketServlet extends JettyWebSocketServlet {

        public PerspectiveWebSocketServlet() {
        }

        @Override
        protected void configure(JettyWebSocketServletFactory jettyWebSocketServletFactory) {
            jettyWebSocketServletFactory.setMaxTextMessageSize(65536);
            jettyWebSocketServletFactory.setCreator(new PerspectiveWebSocketCreator());
        }
    }

    public static class PerspectiveWebSocketCreator implements JettyWebSocketCreator {

        private final Logger logger = LoggerFactory.getLogger(getClass());

        @Override
        public Object createWebSocket(JettyServerUpgradeRequest jettyServerUpgradeRequest, JettyServerUpgradeResponse jettyServerUpgradeResponse) {
            logger.info("createWebSocket");
            return new WebSocketChannel();
        }
    }

    @WebSocket
    public static class WebSocketChannel
    {
        private final Logger logger = LoggerFactory.getLogger(getClass());

        public Session getSession() {
            return memoSession;
        }

        private Session memoSession;

        @OnWebSocketConnect
        public void onWebSocketConnect(Session session)
        {
            try {
                this.memoSession = session;
                String sessionId = String.valueOf(session.hashCode());
                logger.debug("sessionId = {} - onConnect", sessionId);
                sendMessage(session, createSignalingMessage(MESSAGE_READY, ""));
            } catch (Exception e) {
                logger.error("onConnect : Exception : ", e);
            }
        }

        @OnWebSocketMessage
        public void onWebSocketText(String message)
        {
            String sessionId = String.valueOf(getSession().hashCode());
            Session wsSession = getSession();
            try {
                if (!message.equals("HEARTBEAT")) {
                    logger.debug("sessionId = {} - onWebSocketText - LocalAddress = {} - RemoteAddress = {} - message = {}",
                            sessionId,
                            wsSession.getLocalAddress(),
                            wsSession.getRemoteAddress(),
                            message);
                }
                if (message.equals("HEARTBEAT")) {
                    // réponse au heartbeat envoyé par le client JS
                    onWebSocketText_heartbeat(sessionId,message,wsSession);
                } else if (message.startsWith("STOP")) {
...
                }
            } catch (Exception e) {
                logger.error("sessionId = {} - onWebSocketText : Exception : ",sessionId, e);
            }
        }

        @OnWebSocketClose
        public void onWebSocketClose(int statusCode, String reason)
        {
            try {
                String sessionId = String.valueOf(getSession().hashCode());
                logger.debug("sessionId = {} - onWebSocketClose", sessionId);
                stopPipeline(sessionId);
            } catch (Exception e) {
                logger.error("onClose : onWebSocketClose : Exception : ", e);
            }
        }

        @OnWebSocketError
        public void onWebSocketError(Throwable cause)
        {
            //super.onWebSocketError(cause);
        }
    }

```

@paul-griffith help me a lot:

> [@Module with embedded jetty server for websockets break Ignition GAN connections](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343/3):
>
> Can you please share an exemple, for adding a websocket ? Sure it will be better if I can avoid to start a whole new jetty server. or perhaps someone at IA ? @paul-griffith ? can share a snipped to add some custom WebSocket without launching another jetty server.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 16, 2025, 12:56pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/9 "2025-05-16T12:56:49Z")

</div>

The API is moved to new packages. You have to refactor your code. You cannot fix it just in your build configuration.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [May 16, 2025, 12:57pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/10 "2025-05-16T12:57:31Z")

</div>

According to [this](https://jetty.org/docs/jetty/12/programming-guide/migration/11-to-12.html), you would now need something like `org.eclipse.jetty.ee8:jetty-ee8-servlet`.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [May 16, 2025, 1:00pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/11 "2025-05-16T13:00:05Z")

</div>

And you shouldn't need it at all (keep using `provided` scope), because Ignition already has `jetty-ee8-websocket-servlet` as a dependency, which has `jetty-ee8-servlet` as a transitive dependency.

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [May 16, 2025, 4:52pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-jetty-12-upgrade/105482/12 "2025-05-16T16:52:20Z")

</div>

Thanks !  
all things seems to be good for 8.1.49 in my usecase with:

```python
        <!-- Core Jetty server -->
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>12.0.17</version>
            <scope>provided</scope>
        </dependency>

        <!-- Jetty servlet support -->
        <dependency>
            <groupId>org.eclipse.jetty.ee8</groupId>
            <artifactId>jetty-ee8-servlet</artifactId>
            <version>12.0.17</version>
            <scope>provided</scope>
        </dependency>

        <!-- Jetty websocket support -->
        <dependency>
            <groupId>org.eclipse.jetty.ee8.websocket</groupId>
            <artifactId>jetty-ee8-websocket-jetty-api</artifactId>
            <version>12.0.17</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty.ee8.websocket</groupId>
            <artifactId>jetty-ee8-websocket-jetty-server</artifactId>
            <version>12.0.17</version>
            <scope>provided</scope>
        </dependency>

```

and

```python
import org.eclipse.jetty.ee8.websocket.api.Session;
import org.eclipse.jetty.ee8.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.ee8.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.ee8.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.ee8.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.ee8.websocket.api.annotations.WebSocket;

import org.eclipse.jetty.ee8.websocket.server.JettyServerUpgradeRequest;
import org.eclipse.jetty.ee8.websocket.server.JettyServerUpgradeResponse;
import org.eclipse.jetty.ee8.websocket.server.JettyWebSocketCreator;

import org.eclipse.jetty.ee8.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.ee8.websocket.server.JettyWebSocketServletFactory;

```
