html:parse causing jobs to queue?
Sunday, 27 September 2026 · 5 messages · last reply 28 Sep 2026
LV
Lizzi, Vincent27 Sep 2026 18:18 #
Hi BaseX team,
It appears that
html:parse is causing an undefined locking state which can cause jobs to queue.
Here is a minimal example:declare
%rest:path('/parse')
%rest:query-param('content', '{$content}')
function app:parse (
$content as xs:string
) as document-node() {
html:parse($content)
};Normally this function returns a response immediately, but under load with simultaneous requests that doesn't happen, and
job:list-details shows this:<job id="job85" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T15:44:13.888Z">The reads="" is interesting. I would have expected reads="(none)" .
Could the undefined read lock be what is causing API requests to queue waiting for a processing slot to be become available?
Would the new XPath 4.0 function
fn:parse-html() work any differently? I'm about to try using fn:parse-html instead of html:parse() to see what changes.
Thanks,
Vincent
______________________________________________
Vincent M. Lizzi
Head of Information Standards | Taylor & Francis Group
E-Mail: vincent.lizzi at taylorandfrancis.com<mailto:vincent.lizzi at taylorandfrancis.com>
Web: www.tandfonline.com<http://www.tandfonline.com/>
Time zone: US Eastern
Taylor & Francis is a trading name of Informa UK Limited,
registered in England under no. 1072954
"Everything should be made as simple as possible, but not simpler."
Information Classification: General
[cid:1927d7cf-3857-447f-bdf9-4cb8d65b90f6]<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> Book time to meet with me<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature>CG
Christian Grün27 Sep 2026 19:34 #
Hi Vincent,
Can you possibly provide us with a reproducible test case? Does which version of BaseX do you use?
Best,
Christian
Quoted text · Vincent · 50 lines
-------- Original Message -------- On Sunday, 09/27/26 at 18:18 Lizzi, Vincent via BaseX-Talk <basex-talk at mailman.uni-konstanz.de> wrote: > Hi BaseX team, > > It appears that html:parse is causing an undefined locking state which can cause jobs to queue. > > Here is a minimal example: > > declare > %rest:path('/parse') > %rest:query-param('content', '{$content}') > function app:parse ( > $content as xs:string > ) as document-node() { > html:parse($content) > }; > > Normally this function returns a response immediately, but under load with simultaneous requests that doesn't happen, and job:list-details shows this: > > <job id="job85" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T15:44:13.888Z"> > > The reads="" is interesting. I would have expected reads="(none)" . > > Could the undefined read lock be what is causing API requests to queue waiting for a processing slot to be become available? > > Would the new XPath 4.0 function fn:parse-html() work any differently? I'm about to try using fn:parse-html instead of html:parse() to see what changes. > > Thanks, > Vincent > > ______________________________________________ > > Vincent M. Lizzi > > Head of Information Standards | Taylor & Francis Group > > E-Mail: vincent.lizzi at taylorandfrancis.com > > Web: [www.tandfonline.com](http://www.tandfonline.com/) > > Time zone: US Eastern > > Taylor & Francis is a trading name of Informa UK Limited, > > registered in England under no. 1072954 > > "Everything should be made as simple as possible, but not simpler." > > Information Classification: General > https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature [Book time to meet with me](https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature)
LV
Lizzi, Vincent28 Sep 2026 00:40 #
Hi Christian,
Thank you for the quick reply! Here is a complete example. Using BaseX version 12.4, save this code in webapp/app.xqm and run basexhttp.
(:~
: webapp/app.xqm
: Demonstration of multiple calls to an endpoint that uses
html:parse causing a buildup of queued jobs :)
module namespace app = "app";(:~ check job status :)
declare
%rest:path('/jobs')
function app:jobs() {
element jobs {
job:list-details()
}
};
(:~ demonstrate that one call to the endpoint works :)
declare %rest:path('/one')
function app:one () {
job:execute(``[ doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'})) ]``)
};
(:~ generate multiple calls to the endpoint to demonstrate jobs being blocked :)
declare
%rest:path('/many')
function app:start () {
element many {
for $i in (1 to 10)
return job:eval(``[ doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'})) ]``),
job:list-details()
}
};
(:~ endpoint that uses html:parse() or fn:parse-html() :)
declare
%rest:path('/parse')
%rest:query-param('content', '{$content}')
function app:parse (
$content as xs:string
) as document-node() {
html:parse($content)
(:
parse-html($content)
document { <hello>world</hello> }
:)
};Here are the steps using a web browser to send http requests
1.
Request http://localhost:8080/jobs - initially only one job is listed for the /jobs request. 2.
Request http://localhost:8080/one - verify that a single request calling the endpoint works 3.
Request http://localhost:8080/jobs - again only one job is listed for the /jobs request. 4.
Request http://localhost:8080/many - starts background jobs that each call the endpoint 5.
Request http://localhost:8080/jobs - now shows many jobs are queued. 6.
Request http://localhost:8080/jobs - again many jobs are still queued.
Here is an example of the response from /jobs after step 6:
<jobs>
<job id="job99" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.13-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job100" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job101" type="QueryJob" state="running" user="admin" duration="PT19.977S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job102" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job103" type="QueryJob" state="running" user="admin" duration="PT19.977S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job104" type="QueryJob" state="running" user="admin" duration="PT19.976S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job105" type="QueryJob" state="queued" user="admin" start="2026-09-27T18:13:48.131-04:00" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job106" type="QueryJob" state="running" user="admin" duration="PT19.979S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job107" type="QueryJob" state="queued" user="admin" start="2026-09-27T18:13:48.131-04:00" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job108" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job>
<job id="job109" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T18:13:48.137-04:00">(: C:/Users/lizziv/Workspaces/demo/BaseX124/basex/webapp/demo.xqm, 37/10 :) declare %rest:path("/parse") %rest:query-param("content", "{$content}") %basex:inline function Q{app}parse($content_1 as xs:string) as document-node() { html:parse($content_1) }; Q{app}parse("<html><p>text<math><mtext>test</math></html>")</job>
<job id="job120" type="RESTXQ" state="running" user="admin" duration="PT0.001S" reads="(none)" writes="(none)" time="2026-09-27T18:14:08.109-04:00">(: C:/Users/lizziv/Workspaces/demo/BaseX124/basex/webapp/demo.xqm, 10/10 :) declare %rest:path("/jobs") %basex:inline function Q{app}jobs() { element jobs { job:list-details() } }; Q{app}jobs()</job>
</jobs>Note the job with id job109 is an actual request to the /parse endpoint which uses
html:parse(), and it has reads="".
I tried changing the /parse endpoint to use fn:parse-html() instead of html:parse() and the outcome is the same - jobs stay in a queued state. When I tried changing the /parse endpoint to simply return a constructed document the jobs process immediately and no jobs remain queued, as expected.
Looking in the source, I found HtmlParser.java is used by the html:parse() and fn:parse-html() functions, which rely on different java libraries that do the actual work of parsing HTML, but I couldn't pinpoint the problem.
Best,
Vincent
_____________________________________________
Vincent M. Lizzi
Head of Information Standards | Taylor & Francis Group
vincent.lizzi at taylorandfrancis.com<mailto:vincent.lizzi at taylorandfrancis.com>
Time zone: US Eastern
[cid:8f8e1592-dbea-4473-80e4-ec389ff45c8d]<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> Book time to meet with me<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature>Quoted text · Christian Grün · 40 lines
From: Christian Grün <cg at basex.org> Sent: Sunday, September 27, 2026 1:34 PM To: Lizzi, Vincent <Vincent.Lizzi at taylorandfrancis.com>; basex-talk at mailman.uni-konstanz.de <basex-talk at mailman.uni-konstanz.de> Subject: Re: [basex-talk] html:parse causing jobs to queue? Hi Vincent, Can you possibly provide us with a reproducible test case? Does which version of BaseX do you use? Best, Christian -------- Original Message -------- On Sunday, 09/27/26 at 18:18 Lizzi, Vincent via BaseX-Talk <basex-talk at mailman.uni-konstanz.de> wrote: Hi BaseX team, It appears that html:parse is causing an undefined locking state which can cause jobs to queue. Here is a minimal example: declare %rest:path('/parse') %rest:query-param('content', '{$content}') function app:parse ( $content as xs:string ) as document-node() { html:parse($content) }; Normally this function returns a response immediately, but under load with simultaneous requests that doesn't happen, and job:list-details shows this: <job id="job85" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T15:44:13.888Z"> The reads="" is interesting. I would have expected reads="(none)" . Could the undefined read lock be what is causing API requests to queue waiting for a processing slot to be become available? Would the new XPath 4.0 function fn:parse-html() work any differently? I'm about to try using fn:parse-html instead of html:parse() to see what changes. Thanks, Vincent Vincent M. Lizzi Head of Information Standards | Taylor & Francis Group E-Mail: vincent.lizzi at taylorandfrancis.com<mailto:vincent.lizzi at taylorandfrancis.com> Web: www.tandfonline.com<http://www.tandfonline.com/> Time zone: US Eastern Taylor & Francis is a trading name of Informa UK Limited, registered in England under no. 1072954 "Everything should be made as simple as possible, but not simpler." Information Classification: General Information Classification: General [cid:1927d7cf-3857-447f-bdf9-4cb8d65b90f6]<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> Book time to meet with me<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature>
CG
Christian Grün28 Sep 2026 15:03 #
Thanks, Vincent.
My guess is that it has been fixed in BaseX 13, presumably by [1]; at least I couldn’t reproduce it anymore. Can you confirm this, or do you have doubts?
Best,
Christian
[1] https://github.com/BaseXdb/basex/commit/ccb99434a5d4677fcf6119272ac2de5cb6e5e0d0
Quoted text · Vincent · 166 lines
Lizzi, Vincent via BaseX-Talk <basex-talk at mailman.uni-konstanz.de> schrieb am Montag, 28. September 2026 um 00:41: > Hi Christian, > > Thank you for the quick reply! Here is a complete example. Using BaseX version 12.4, save this code in webapp/app.xqm and run basexhttp. > > (:~ > : webapp/app.xqm > : Demonstration of multiple calls to an endpoint that uses html:parse causing a buildup of queued jobs > :) > > module namespace app = "app"; > > (:~ check job status :) > declare > %rest:path('/jobs') > function app:jobs() { > element jobs { > job:list-details() > } > }; > > (:~ demonstrate that one call to the endpoint works :) > declare %rest:path('/one') > function app:one () { > job:execute(``[ doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'})) ]``) > }; > > (:~ generate multiple calls to the endpoint to demonstrate jobs being blocked :) > declare > %rest:path('/many') > function app:start () { > element many { > for $i in (1 to 10) > return job:eval(``[ doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'})) ]``), > job:list-details() > } > }; > > (:~ endpoint that uses html:parse() or fn:parse-html() :) > declare > %rest:path('/parse') > %rest:query-param('content', '{$content}') > function app:parse ( > $content as xs:string > ) as document-node() { > html:parse($content) > (: > parse-html($content) > document { <hello>world</hello> } > :) > }; > > Here are the steps using a web browser to send http requests > > - Request http://localhost:8080/jobs - initially only one job is listed for the /jobs request. > - Request http://localhost:8080/one - verify that a single request calling the endpoint works > - Request http://localhost:8080/jobs - again only one job is listed for the /jobs request. > - Request http://localhost:8080/many - starts background jobs that each call the endpoint > - Request http://localhost:8080/jobs - now shows many jobs are queued. > - Request http://localhost:8080/jobs - again many jobs are still queued. > > Here is an example of the response from /jobs after step 6: > > <jobs> > <job id="job99" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.13-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job100" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job101" type="QueryJob" state="running" user="admin" duration="PT19.977S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job102" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job103" type="QueryJob" state="running" user="admin" duration="PT19.977S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job104" type="QueryJob" state="running" user="admin" duration="PT19.976S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job105" type="QueryJob" state="queued" user="admin" start="2026-09-27T18:13:48.131-04:00" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job106" type="QueryJob" state="running" user="admin" duration="PT19.979S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job107" type="QueryJob" state="queued" user="admin" start="2026-09-27T18:13:48.131-04:00" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job108" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> > <job id="job109" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T18:13:48.137-04:00">(: C:/Users/lizziv/Workspaces/demo/BaseX124/basex/webapp/demo.xqm, 37/10 :) declare %rest:path("/parse") %rest:query-param("content", "{$content}") %basex:inline function Q{app}parse($content_1 as xs:string) as document-node() { html:parse($content_1) }; Q{app}parse("<html><p>text<math><mtext>test</math></html>")</job> > <job id="job120" type="RESTXQ" state="running" user="admin" duration="PT0.001S" reads="(none)" writes="(none)" time="2026-09-27T18:14:08.109-04:00">(: C:/Users/lizziv/Workspaces/demo/BaseX124/basex/webapp/demo.xqm, 10/10 :) declare %rest:path("/jobs") %basex:inline function Q{app}jobs() { element jobs { job:list-details() } }; Q{app}jobs()</job> > </jobs> > > Note the job with id job109 is an actual request to the /parse endpoint which uses html:parse(), and it has reads="". > > I tried changing the /parse endpoint to use fn:parse-html() instead of html:parse() and the outcome is the same - jobs stay in a queued state. When I tried changing the /parse endpoint to simply return a constructed document the jobs process immediately and no jobs remain queued, as expected. > > Looking in the source, I found HtmlParser.java is used by the html:parse() and fn:parse-html() functions, which rely on different java libraries that do the actual work of parsing HTML, but I couldn't pinpoint the problem. > > Best, > Vincent > > _____________________________________________ > > Vincent M. Lizzi > > Head of Information Standards | Taylor & Francis Group > > vincent.lizzi at taylorandfrancis.com > > Time zone: US Eastern > > https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature [Book time to meet with me](https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature) > > --------------------------------------------------------------- > > From: Christian Grün <cg at basex.org> > Sent: Sunday, September 27, 2026 1:34 PM > To: Lizzi, Vincent <Vincent.Lizzi at taylorandfrancis.com>; basex-talk at mailman.uni-konstanz.de <basex-talk at mailman.uni-konstanz.de> > Subject: Re: [basex-talk] html:parse causing jobs to queue? > > Hi Vincent, > > Can you possibly provide us with a reproducible test case? Does which version of BaseX do you use? > > Best, > Christian > > -------- Original Message -------- > On Sunday, 09/27/26 at 18:18 Lizzi, Vincent via BaseX-Talk <basex-talk at mailman.uni-konstanz.de> wrote: > >> Hi BaseX team, >> >> It appears that html:parse is causing an undefined locking state which can cause jobs to queue. >> >> Here is a minimal example: >> >> declare >> %rest:path('/parse') >> %rest:query-param('content', '{$content}') >> function app:parse ( >> $content as xs:string >> ) as document-node() { >> html:parse($content) >> }; >> >> Normally this function returns a response immediately, but under load with simultaneous requests that doesn't happen, and job:list-details shows this: >> >> <job id="job85" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T15:44:13.888Z"> >> >> The reads="" is interesting. I would have expected reads="(none)" . >> >> Could the undefined read lock be what is causing API requests to queue waiting for a processing slot to be become available? >> >> Would the new XPath 4.0 function fn:parse-html() work any differently? I'm about to try using fn:parse-html instead of html:parse() to see what changes. >> >> Thanks, >> Vincent >> >> ______________________________________________ >> >> Vincent M. Lizzi >> >> Head of Information Standards | Taylor & Francis Group >> >> E-Mail: vincent.lizzi at taylorandfrancis.com >> >> Web: [www.tandfonline.com](http://www.tandfonline.com/) >> >> Time zone: US Eastern >> >> Taylor & Francis is a trading name of Informa UK Limited, >> >> registered in England under no. 1072954 >> >> "Everything should be made as simple as possible, but not simpler." >> >> Information Classification: General >> >> Information Classification: General >> https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature [Book time to meet with me](https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature)
LV
Lizzi, Vincent28 Sep 2026 16:29 #
Hi Christian,
Amazing! I just tried with the latest snapshot of BaseX 13 and it's now working. The endpoints that use
html:parse() now have reads="(none)" and process without any blocks.
Thank you,
Vincent
_____________________________________________
Vincent M. Lizzi
Head of Information Standards | Taylor & Francis Group
vincent.lizzi at taylorandfrancis.com<mailto:vincent.lizzi at taylorandfrancis.com>
Time zone: US Eastern
[cid:bc2aea7d-d363-419b-9d5f-18dc565c51eb]<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> Book time to meet with me<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature>Quoted text · Christian Grün · 134 lines
From: Christian Grün <cg at basex.org> Sent: Monday, September 28, 2026 9:03 AM To: Lizzi, Vincent <Vincent.Lizzi at taylorandfrancis.com> Cc: basex-talk at mailman.uni-konstanz.de <basex-talk at mailman.uni-konstanz.de> Subject: AW: [basex-talk] Re: html:parse causing jobs to queue? Thanks, Vincent. My guess is that it has been fixed in BaseX 13, presumably by [1]; at least I couldn’t reproduce it anymore. Can you confirm this, or do you have doubts? Best, Christian [1] https://github.com/BaseXdb/basex/commit/ccb99434a5d4677fcf6119272ac2de5cb6e5e0d0<https://github.com/BaseXdb/basex/commit/ccb99434a5d4677fcf6119272ac2de5cb6e5e0d0> Lizzi, Vincent via BaseX-Talk <basex-talk at mailman.uni-konstanz.de> schrieb am Montag, 28. September 2026 um 00:41: Hi Christian, Thank you for the quick reply! Here is a complete example. Using BaseX version 12.4, save this code in webapp/app.xqm and run basexhttp. (:~ : webapp/app.xqm : Demonstration of multiple calls to an endpoint that uses html:parse causing a buildup of queued jobs :) module namespace app = "app"; (:~ check job status :) declare %rest:path('/jobs') function app:jobs() { element jobs { job:list-details() } }; (:~ demonstrate that one call to the endpoint works :) declare %rest:path('/one') function app:one () { job:execute(``[ doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'})) ]``) }; (:~ generate multiple calls to the endpoint to demonstrate jobs being blocked :) declare %rest:path('/many') function app:start () { element many { for $i in (1 to 10) return job:eval(``[ doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'})) ]``), job:list-details() } }; (:~ endpoint that uses html:parse() or fn:parse-html() :) declare %rest:path('/parse') %rest:query-param('content', '{$content}') function app:parse ( $content as xs:string ) as document-node() { html:parse($content) (: parse-html($content) document { <hello>world</hello> } :) }; Here are the steps using a web browser to send http requests 1. Request http://localhost:8080/jobs<http://localhost:8080/jobs> - initially only one job is listed for the /jobs request. 2. Request http://localhost:8080/one<http://localhost:8080/one> - verify that a single request calling the endpoint works 3. Request http://localhost:8080/jobs<http://localhost:8080/jobs> - again only one job is listed for the /jobs request. 4. Request http://localhost:8080/many<http://localhost:8080/many> - starts background jobs that each call the endpoint 5. Request http://localhost:8080/jobs<http://localhost:8080/jobs> - now shows many jobs are queued. 6. Request http://localhost:8080/jobs<http://localhost:8080/jobs> - again many jobs are still queued. Here is an example of the response from /jobs after step 6: <jobs> <job id="job99" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.13-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job100" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job101" type="QueryJob" state="running" user="admin" duration="PT19.977S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job102" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job103" type="QueryJob" state="running" user="admin" duration="PT19.977S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job104" type="QueryJob" state="running" user="admin" duration="PT19.976S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job105" type="QueryJob" state="queued" user="admin" start="2026-09-27T18:13:48.131-04:00" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job106" type="QueryJob" state="running" user="admin" duration="PT19.979S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job107" type="QueryJob" state="queued" user="admin" start="2026-09-27T18:13:48.131-04:00" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job108" type="QueryJob" state="running" user="admin" duration="PT19.978S" reads="(global)" writes="(none)" time="2026-09-27T18:13:48.131-04:00">doc(web:create-url('http://localhost:8080/parse', {'content': '<html><p>text<math><mtext>test</math></html>'}))</job> <job id="job109" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T18:13:48.137-04:00">(: C:/Users/lizziv/Workspaces/demo/BaseX124/basex/webapp/demo.xqm, 37/10 :) declare %rest:path("/parse") %rest:query-param("content", "{$content}") %basex:inline function Q{app}parse($content_1 as xs:string) as document-node() { html:parse($content_1) }; Q{app}parse("<html><p>text<math><mtext>test</math></html>")</job> <job id="job120" type="RESTXQ" state="running" user="admin" duration="PT0.001S" reads="(none)" writes="(none)" time="2026-09-27T18:14:08.109-04:00">(: C:/Users/lizziv/Workspaces/demo/BaseX124/basex/webapp/demo.xqm, 10/10 :) declare %rest:path("/jobs") %basex:inline function Q{app}jobs() { element jobs { job:list-details() } }; Q{app}jobs()</job> </jobs> Note the job with id job109 is an actual request to the /parse endpoint which uses html:parse(), and it has reads="". I tried changing the /parse endpoint to use fn:parse-html() instead of html:parse() and the outcome is the same - jobs stay in a queued state. When I tried changing the /parse endpoint to simply return a constructed document the jobs process immediately and no jobs remain queued, as expected. Looking in the source, I found HtmlParser.java is used by the html:parse() and fn:parse-html() functions, which rely on different java libraries that do the actual work of parsing HTML, but I couldn't pinpoint the problem. Best, Vincent Vincent M. Lizzi Head of Information Standards | Taylor & Francis Group vincent.lizzi at taylorandfrancis.com<mailto:vincent.lizzi at taylorandfrancis.com> Time zone: US Eastern [cid:8f8e1592-dbea-4473-80e4-ec389ff45c8d]<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> Book time to meet with me<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> From: Christian Grün <cg at basex.org<mailto:cg at basex.org>> Sent: Sunday, September 27, 2026 1:34 PM To: Lizzi, Vincent <Vincent.Lizzi at taylorandfrancis.com<mailto:Vincent.Lizzi at taylorandfrancis.com>>; basex-talk at mailman.uni-konstanz.de<mailto:basex-talk at mailman.uni-konstanz.de> <basex-talk at mailman.uni-konstanz.de<mailto:basex-talk at mailman.uni-konstanz.de>> Subject: Re: [basex-talk] html:parse causing jobs to queue? Hi Vincent, Can you possibly provide us with a reproducible test case? Does which version of BaseX do you use? Best, Christian -------- Original Message -------- On Sunday, 09/27/26 at 18:18 Lizzi, Vincent via BaseX-Talk <basex-talk at mailman.uni-konstanz.de<mailto:basex-talk at mailman.uni-konstanz.de>> wrote: Hi BaseX team, It appears that html:parse is causing an undefined locking state which can cause jobs to queue. Here is a minimal example: declare %rest:path('/parse') %rest:query-param('content', '{$content}') function app:parse ( $content as xs:string ) as document-node() { html:parse($content) }; Normally this function returns a response immediately, but under load with simultaneous requests that doesn't happen, and job:list-details shows this: <job id="job85" type="RESTXQ" state="queued" user="admin" reads="" writes="(none)" time="2026-09-27T15:44:13.888Z"> The reads="" is interesting. I would have expected reads="(none)" . Could the undefined read lock be what is causing API requests to queue waiting for a processing slot to be become available? Would the new XPath 4.0 function fn:parse-html() work any differently? I'm about to try using fn:parse-html instead of html:parse() to see what changes. Thanks, Vincent Vincent M. Lizzi Head of Information Standards | Taylor & Francis Group E-Mail: vincent.lizzi at taylorandfrancis.com<mailto:vincent.lizzi at taylorandfrancis.com> Web: www.tandfonline.com<http://www.tandfonline.com/> Time zone: US Eastern Taylor & Francis is a trading name of Informa UK Limited, registered in England under no. 1072954 "Everything should be made as simple as possible, but not simpler." Information Classification: General Information Classification: General [cid:1927d7cf-3857-447f-bdf9-4cb8d65b90f6]<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> Book time to meet with me<https://outlook.office.com/bookwithme/user/aa80d42cbb5b46dba06a5ad241d7665b at taylorandfrancis.com?anonymous&ep=owaSlotsEmailSignature> Information Classification: General
Written for BaseX 12.4. BaseX may have changed since: please check the current documentation.
⚡Generated with XQuery