Add WebSocket module and streaming query evaluation to exist-core#6145
Open
joewiz wants to merge 12 commits intoeXist-db:developfrom
Open
Add WebSocket module and streaming query evaluation to exist-core#6145joewiz wants to merge 12 commits intoeXist-db:developfrom
joewiz wants to merge 12 commits intoeXist-db:developfrom
Conversation
Dependency version changes: - Jetty: 11.0.25 -> 12.0.16 - Jakarta Servlet API: 5.0.0 -> 6.0.0 (EE10) - Milton servlet: 1.8.1.3-jakarta5 -> 1.8.1.3-jakarta-ee10 (fixes setStatus(int,String) removal in Servlet 6.0; temporarily uses com.evolvedbinary.thirdparty groupId — needs republishing under org.exist-db.thirdparty) Jetty 12 artifact coordinate changes: - Servlet-layer: org.eclipse.jetty -> org.eclipse.jetty.ee10 (annotations, servlet, webapp, plus, jndi) - WebSocket: org.eclipse.jetty.websocket -> org.eclipse.jetty.ee10.websocket - JAAS: removed as separate dep (now in jetty-security core module) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Handler model: - HandlerCollection -> Handler$Sequence (constructor takes Array arg) - Server constructor arg: threadpool -> threadPool (case-sensitive) Deployment: - Replaced ContextProvider/scanner with inline addHandler on ContextHandlerCollection Security and class paths: - ConstraintSecurityHandler -> org.eclipse.jetty.ee10.servlet.security - JAASLoginService -> org.eclipse.jetty.security.jaas - DefaultServlet/IntrospectorCleaner -> ee10 packages - ELContextCleaner removed (obsolete) Compliance and other: - MultiPartFormDataCompliance -> MultiPartCompliance - UriCompliance: LEGACY -> UNSAFE (non-ASCII path support) - SecureRequestCustomizer: constructor args -> setter-based - GzipHandler: use addIncludedMethods - Removed org.eclipse.jetty.util.log.Log references Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
JettyStart.java: Handler model rewrite, ResourceFactory, ee10 packages WebAppContext.java: extends ee10 WebAppContext HttpServletRequestWrapper.java: Servlet 6.0 additions/removals XQueryURLRewrite.java, HttpServletResponseAdapter.java: removed setStatus(int, String) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- All web-app version="5.0" -> "6.0" with Servlet 6.0 schema refs - Distribution XSDs: real Jakarta EE 10 schemas from jakarta.ee - @ignore GetDataTest HTTP/0.9 and HTTP/1.0 tests (Jetty 12) - DbStore2Test: Jetty 12 ResourceHandler/Handler.Sequence API Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
New LockTest with 3 tests: - lockAndUnlockXmlDocument: LOCK returns token, UNLOCK succeeds - lockAndUnlockBinDocument: same for binary documents - relockReturnsFreshToken: re-LOCK by same user replaces the lock Ensures LOCK support (Milton 1.x LockableResource) is preserved across the Jetty 12 upgrade. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
New package: org.exist.xquery.functions.websocket WebSocket endpoint (@serverendpoint("/ws")): - Channel-based pub/sub: clients send {"channel": "name"} to subscribe - sendAll(channel, data) broadcasts to subscribed clients - 500ms heartbeat ping keeps connections alive through proxies - Session management via ConcurrentHashMap XQuery module (namespace: http://exist-db.org/xquery/websocket, prefix: ws): - ws:log($items) / ws:log($channel, $items) — log to channel - ws:send($channel, $items) — send JSON to channel - ws:broadcast($items) — send to all clients - ws:channel-count($channel) — count subscribers Backward-compatible console module (http://exist-db.org/xquery/console): - console:log() and console:send() delegate to WebSocketModule - Existing monex XQuery code works unchanged Ported from monex's RemoteConsoleEndpoint/RemoteConsoleAdapter/ConsoleModule. Dependencies: - jakarta.websocket-client-api 2.1.0 (provided scope) - jakarta.websocket-api 2.1.0 (provided scope) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Jetty 12 integration: - JettyStart.configureWebSocket() finds the ServletContextHandler in the server's handler tree and registers the /ws endpoint via JakartaWebSocketServletContainerInitializer.configure() - WebSocketEndpoint.initialize() sets up the adapter and heartbeat scheduler during server startup - Added jetty-ee10-websocket-jakarta-server dependency to exist-core Integration tests (WebSocketEndpointTest): - connectAndReceiveHeartbeat: client connects, receives ping - subscribeToChannelAndReceiveMessage: client subscribes to channel, ws:send() delivers message to subscribed client - channelCountReflectsSubscribers: ws:channel-count() returns correct subscriber count Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
2d3f524 to
56f81a4
Compare
joewiz
added a commit
to joewiz/monex
that referenced
this pull request
Mar 17, 2026
BREAKING CHANGE: Requires eXist-db 7.0+ with WebSocket support. Build system migrated from Apache Maven to Node.js/Gulp, following the pattern established in eXist-db/semver.xq#69. Java removal (requires eXist-db/exist#6145 WebSocket module): - Removed all Java source (6 files, ~630 LOC) - WebSocket/Console functions now provided by exist-core - JMXToken reimplemented as pure XQuery monex:jmx-token() - JS clients updated: /rconsole → /ws - Cypress tests updated to match De-mavenization (modeled on eXist-db/semver.xq#69): - Replaced pom.xml + xar-assembly.xml with package.json + gulpfile.js - XAR built via gulp: template substitution → copy → zip - expath-pkg.xml.tmpl and repo.xml.tmpl with @variable@ placeholders - build.xml Ant wrapper for backward compatibility - New GitHub Actions CI workflow (Node.js-based) - npm run build / npm run deploy / npm test Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
joewiz
added a commit
to joewiz/monex
that referenced
this pull request
Mar 17, 2026
BREAKING CHANGE: Requires eXist-db 7.0+ with WebSocket support. Build system migrated from Apache Maven to Node.js/Gulp, following the pattern established in eXist-db/semver.xq#69. Java removal (requires eXist-db/exist#6145 WebSocket module): - Removed all Java source (6 files, ~630 LOC) - WebSocket/Console functions now provided by exist-core - JMXToken reimplemented as pure XQuery monex:jmx-token() - JS clients updated: /rconsole → /ws - Cypress tests updated to match De-mavenization (modeled on eXist-db/semver.xq#69): - Replaced pom.xml + xar-assembly.xml with package.json + gulpfile.js - XAR built via gulp: template substitution → copy → zip - expath-pkg.xml.tmpl and repo.xml.tmpl with @variable@ placeholders - build.xml Ant wrapper for backward compatibility - New GitHub Actions CI workflow (Node.js-based) - npm run build / npm run deploy / npm test Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
joewiz
added a commit
to joewiz/monex
that referenced
this pull request
Mar 17, 2026
BREAKING CHANGE: Requires eXist-db 7.0+ with WebSocket support. Build system migrated from Apache Maven to Node.js/Gulp, following the pattern established in eXist-db/semver.xq#69. Java removal (requires eXist-db/exist#6145 WebSocket module): - Removed all Java source (6 files, ~630 LOC) - WebSocket/Console functions now provided by exist-core - JMXToken reimplemented as pure XQuery monex:jmx-token() - JS clients updated: /rconsole → /ws - Cypress tests updated to match De-mavenization (modeled on eXist-db/semver.xq#69): - Replaced pom.xml + xar-assembly.xml with package.json + gulpfile.js - XAR built via gulp: template substitution → copy → zip - expath-pkg.xml.tmpl and repo.xml.tmpl with @variable@ placeholders - build.xml Ant wrapper for backward compatibility - New GitHub Actions CI workflow (Node.js-based) - npm run build / npm run deploy / npm test Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
console:log is now a valid built-in function via ConsoleCompatModule on the WebSocket branch. Use nonexistent:foo instead to test unknown function error handling. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…tion Add a new WebSocket endpoint at /ws/eval that enables real-time, streaming XQuery evaluation with progress reporting, cancellation, and timing breakdown. This is the XQuery equivalent of a modern database's interactive query console protocol. Protocol supports: - eval: Execute queries with streaming results in configurable chunks - cancel: Cancel running queries via XQueryWatchDog - compile: Compile-check queries without execution Server responds with typed JSON messages: - progress: Phase updates (parsing/compiling/evaluating/serializing) - result: Serialized data chunks with more/done indicators - error: XPath errors with code, message, line, column - cancelled: Confirmation with items-produced count - compile: Success/failure with diagnostics Authentication via Basic auth on WebSocket handshake, falling back to guest. Queries execute on worker threads with BrokerPool integration. New classes in org.exist.http.ws: - EvalWebSocketEndpoint: @serverendpoint with auth configurator - EvalSession: Per-connection state and query cancellation - QueryExecutor: XQuery execution with streaming and progress - EvalProtocol: JSON message parsing and generation 13 integration tests covering: simple eval, variables, streaming chunks, cancellation, compile check, progress, timing, serialization options, timeout, error handling. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Bridge /ws/eval query lifecycle events to the /ws pub/sub channel system, enabling admin monitoring clients to receive real-time query progress. - QueryMonitorBroadcaster: broadcasts started/progress/completed/error/ cancelled events to _monitor channel; periodic 1s snapshot of ALL running queries from ProcessMonitor (covers REST, URL rewrite, etc.) - EvalWebSocketEndpoint: admin-cancel action for DBA users to kill any running query cross-session via ProcessMonitor - WebSocketEndpoint: sendAll made public; snapshot scheduler added - EvalProtocol: ACTION_ADMIN_CANCEL constant Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
11 tasks
joewiz
added a commit
to joewiz/xst
that referenced
this pull request
Mar 22, 2026
Include required 'id' field in all messages, handle chunked 'result' messages with 'more' boolean, read timing from final result chunk, and handle 'cancelled' response type for SIGINT cancellation. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
joewiz
added a commit
to joewiz/xst
that referenced
this pull request
Mar 22, 2026
Add streaming query execution via WebSocket to the existing exec command. --stream connects to the /exist/ws/eval endpoint and prints results as they arrive, with Ctrl+C cancellation support. --timing reports execution timing in both HTTP and streaming modes. Depends on the server-side WebSocket eval endpoint (eXist-db/exist#6145). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add 10 new integration tests (23 total) covering: - Concurrent queries: two eval actions on the same connection - Large result streaming: 100K items with chunk-size verification - Binary result handling: xs:base64Binary serialization - Map/array result serialization: adaptive output method - Module-load-path resolution: import module stored in /db - Admin-cancel permission check: non-DBA gets permission denied - Monitor channel: _monitor subscription receives query lifecycle events - Connection cleanup: disconnect mid-query releases server resources - Error recovery: invalid JSON doesn't kill the connection - Rapid cancel: cancel immediately after eval before compilation Also fix long-running query pattern in timeout tests: use string($i) to force watchdog checks instead of lazy RangeSequence. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
CI runners are 3-5x slower than local machines. Increase await() timeouts from 10s to 30s in cancellation, maxExecutionTime, and rapidCancel tests. Also increase max-execution-time from 500ms to 2000ms to ensure the watchdog has time to activate on slow runners. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds WebSocket infrastructure to exist-core with two endpoints:
/ws— Channel-based pub/sub messaging (ported from monex) with_monitorquery lifecycle broadcasting/ws/eval— Real-time streaming XQuery evaluation with cancellation, progress reporting, and timing breakdownThis is the foundation for removing Java code from monex, enabling future LSP wire protocol support, and making eXist's interactive tools feel modern and responsive.
Based on: PR #6144 (Jetty 12 upgrade) — should merge after that PR.
/ws— Channel Pub/SubPorted from monex's
RemoteConsoleEndpointinto a general-purpose WebSocket module.Clients connect, subscribe to channels via
{"channel": "name"}, and receive JSON messages. A 500ms heartbeat ping keeps connections alive through proxies._monitorChannel (new)Admin clients can subscribe to the
_monitorchannel to receive real-time query lifecycle events:started,progress,completed,error,cancelledevents from/ws/evalqueriesXQuery Functions
ws:log($items as item()*) as empty-sequence()ws:log($channel, $items)ws:send($channel, $items)ws:broadcast($items as item()*)ws:channel-count($channel) as xs:integer/ws/eval— Streaming Query Evaluation (new)A WebSocket endpoint for real-time XQuery evaluation — the XQuery equivalent of a modern database's interactive query console protocol.
Protocol (JSON over WebSocket)
Client → Server:
evalcancelcompileadmin-cancelServer → Client:
progressresultmore/done indicators and timingerrorcancelledcompileKey Features
cancelaction sets a flag onXQueryWatchDog. Works mid-evaluation and mid-serialization.system:kill-running-xquery)._monitorsubscribers.Example
New Classes
WebSocketEndpointo.e.xquery.functions.websocket@ServerEndpoint("/ws")— channel pub/sub, heartbeatWebSocketModuleo.e.xquery.functions.websocketws:namespace)ConsoleCompatModuleo.e.xquery.functions.websocketconsole:namespaceEvalWebSocketEndpointo.e.http.ws@ServerEndpoint("/ws/eval")— streaming evalEvalSessiono.e.http.wsQueryExecutoro.e.http.wsEvalProtocolo.e.http.wsQueryMonitorBroadcastero.e.http.ws_monitorchannelBackward Compatibility
The
console:namespace (http://exist-db.org/xquery/console) is provided byConsoleCompatModule, which delegates toWebSocketModule. Existing monex XQuery code usingconsole:log()works unchanged.Test plan
WebSocket pub/sub (3 tests):
Eval endpoint (20 tests):
1 + 1→"2")Total: 23 integration tests
What This Enables
_monitorchannelxst eval --streamprints results as they arriveCI Status
Integration tests pass on macOS and ubuntu. Known CI issues:
🤖 Generated with Claude Code