Project

Profile

Help

Need advice on how to use SaxonC 11.1 Python API in web application

Added by Martin Honnen 5 months ago

I started writing some more code using the Python API of SaxonC 11.1 HE and while command line programs run fine, any attempts to use similar code in a simple web application results in an error like "JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x0000000000a6730e" after the very first request.

I can't say I have lots of experience writing web applications in Python, so I might be doing something wrong but I would appreciate any advice on how/where to create/store the PySaxonProcessor object or how to organize the code to avoid the error.

A simple Python code is

"""
This script runs the application using a development server.
It contains the definition of routes and views for the application.
"""

from flask import Flask, request
app = Flask(__name__)

from saxonc import *

proc = PySaxonProcessor(license = False)

# Make the WSGI interface available at the top level so wfastcgi can get it.
wsgi_app = app.wsgi_app


@app.route('/')
def hello():
    """Renders a sample page."""
    return "Hello World!"

@app.route('/xquery', methods=['POST'])
def xquery():
    request_data = request.get_json()
    result = evaluate_xquery(proc, request_data)

    return result


def evaluate_xquery(proc, request_data):

    xquery_processor = proc.new_xquery_processor()
    
    if 'inputType' in request_data:
        if request_data['inputType'] == 'xml':
            input_node = proc.parse_xml(xml_text = request_data['inputData'])
            xquery_processor.set_context(xdm_item = input_node)
        elif request_data['inputType'] == 'json':
            xquery_processor1 = proc.new_xquery_processor()
            xquery_processor1.set_parameter('json-text', proc.make_string_value(request_data['inputData']))               
            input_json = xquery_processor1.run_query_to_value(query_text = 'declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; declare option output:method "adaptive"; declare variable $json-text as xs:string external; parse-json($json-text)')
            xquery_processor.set_context(xdm_item = input_json.head)
    result = xquery_processor.run_query_to_string(query_text = request_data['inputCode'])
    
    return result

if __name__ == '__main__':
    import os
    HOST = os.environ.get('SERVER_HOST', 'localhost')
    try:
        PORT = int(os.environ.get('SERVER_PORT', '5555'))
    except ValueError:
        PORT = 5555
    app.run(HOST, PORT)

The app starts fine and I can do a single request fine (at least as far as running the client code using JavaScript is concerned that does a fetch and receives a result:

fetch('/xquery', { method: 'POST', headers : { 'Content-Type' : 'application/json'} , body : JSON.stringify({inputCode : '?*', 'inputData' : '[1,2,3]', 'inputType' : 'json' }) }).then(response => response.text()).then(text => console.log(text))

gives <?xml version="1.0" encoding="UTF-8"?>1 2 3 but without any further requests the Python command console already shows

127.0.0.1 - - [11/Feb/2022 10:09:02] "←[37mPOST /xquery HTTP/1.1←[0m" 200 -

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x0000000000a6730e
Please, contact the vendor of the application.
Crash dump will be written to "C:\Users\marti\source\repos\SaxonCPythonAPI\SaxonCPythonAPI\jet_dump_27600.dmp"
Extra information about error is saved in the "jet_err_27600.txt" file.

ao the server handled the /xquery request fine but then the JET runtime gives an error.

That text files starts as shown below, so it seems a memory access violation:

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x0000000000a6730e
Please, contact the vendor of the application.
Crash dump will be written to "C:\Users\marti\source\repos\SaxonCPythonAPI\SaxonCPythonAPI\jet_dump_27600.dmp"

Exception 0xC0000005 (EXCEPTION_ACCESS_VIOLATION) at 0x0000000000a6730e (C:\Program Files\Saxonica\SaxonCHE11.1\libsaxonhec.dll+0x66730e)
Failed to read memory at 0x0000009c0d9f0000

Version Information:

  Java version: 1.8.0_181
  Excelsior JET 15.30 Enterprise edition
  JET Profile: OpenJDK version: 1.8.0_181; JET update level: 6; CPU architecture: amd64
  Runtime: Server
  CPU features: cmov mmx sse sse2 sse3 ssse3 sse4.1 sse4.2 avx avx2 fma f16c lzcnt popcnt bmi1 bmi2 adx cx8 cx16 movbe avx-512f
  Application was deployed

Options and system properties:

  -Djet.jit.disable.resolution=
  -Djet.gc.heaplimit=0
  -Djet.stack.trace=

Entry point type: Invocation API

Command line: "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python39_64\python.exe" "c:\program files\microsoft visual studio\2022\community\common7\ide\extensions\microsoft\python\core\debugpy" --connect 127.0.0.1:51423 --configure-subProcess False --configure-qt none --adapter-access-token 7eb4ea4aa456cafc14ab9e4d8167ff046cd2b609e8cd08916977861600df5764 C:\Users\marti\source\repos\SaxonCPythonAPI\SaxonCPythonAPI\app.py

OS:

Windows 10 build 19044

JET-compiled Components:

C:\Program Files\Saxonica\SaxonCHE11.1\libsaxonhec.dll dll, version info: jet-1530-mp1 (ent, en)

Replies (35)

Please register to reply

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by Martin Honnen 4 months ago

I have now tried to get rid of all the web api or web framework stuff and I have tried to use a simple Python multithreading app with SaxonC HE 11.2, it also gets that EXCEPTION_ACCESS_VIOLATION:

import threading
import time

from saxonc import *

exitFlag = 0

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter, saxon_proc):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
      self.saxon_proc = saxon_proc
      self.xquery_processor = saxon_proc.new_xquery_processor()
   def run(self):
      print ("Starting " + self.name)
      example(self.name, self.counter, 5, self.xquery_processor)
      print ("Exiting " + self.name)

def example(threadName, delay, counter, xquery_processor):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print(xquery_processor.run_query_to_string(query_text = '"Hello from SaxonC: " || current-dateTime()'))
      counter -= 1


with PySaxonProcessor(license = False) as saxon_proc:
    # Create new threads
    thread1 = myThread(1, "Thread-1", 1, saxon_proc)
    thread2 = myThread(2, "Thread-2", 2, saxon_proc)

    # Start new Threads
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
    print ("Exiting Main Thread")

Output:

SaxonProc constructor(l) called
SaxonProc constructor: jvm exists! jvmCreatedCPP=1
SaxonProc constructor(l) called
New processor created, Processor: -29383024
New processor created, Processor: -29383024
Starting Thread-1
Starting Thread-2
DEBUG: SaxonCAPI: param-name: qs, type of Value= java.lang.String
qs
<?xml version="1.0" encoding="UTF-8"?>Hello from SaxonC: 2022-03-05T11:35:18.791+01:00
DEBUG: SaxonCAPI: param-name: qs, type of Value= java.lang.String
qs
<?xml version="1.0" encoding="UTF-8"?>Hello from SaxonC: 2022-03-05T11:35:19.691+01:00
DEBUG: SaxonCAPI: param-name: qs, type of Value= java.lang.String
qs

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x0000000000a6730e

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by Martin Honnen 4 months ago

That output on Windows at least shows that calling SaxonC works twice before crashing, on Linux it looks to go down earlier:

python3 Python3SimpleThreadingSaxonCHE112Ex1.py
Starting Thread-1
Starting Thread-2

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x00007ff275ebed49
Please, contact the vendor of the application.
Core dump will be written to "/mnt/wslg/dumps/core.%e"
Extra information about error is saved in the "jet_err_8068.txt" file.
JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x00007ff275ebed49
Please, contact the vendor of the application.
Core dump will be written to "/mnt/wslg/dumps/core.%e"

Signal 11 (SIGSEGV)
siginfo: si_signo 11, si_errno 0, si_code 1, si_addr 0x000000000000000f

Version Information:

  Java version: 1.8.0_181
  Excelsior JET 15.30 Enterprise edition
  JET Profile: OpenJDK version: 1.8.0_181; JET update level: 6; CPU architecture: amd64
  Runtime: Server
  CPU features: cmov mmx sse sse2 sse3 ssse3 sse4.1 sse4.2 avx avx2 fma f16c lzcnt popcnt bmi1 bmi2 adx cx8 cx16 movbe
  Application was deployed

Options and system properties:

  -Djet.jit.disable.resolution=
  -Djet.gc.heaplimit=0
  -Djet.stack.trace=

Entry point type: Invocation API

Command line: "python3" "Python3SimpleThreadingSaxonCHE112Ex1.py"

OS:

Ubuntu 20.04.4 LTS
Linux 5.10.60.1-microsoft-standard-WSL2 #1 SMP Wed Aug 25 23:20:18 UTC 2021 x86_64
glibc 2.31

JET-compiled Components:

/usr/lib/libsaxonhec.so dll, version info: jet-1530-mp1 (ent, en)

Is there any unit test trying to use SaxonC 11 with Python and multithreading?

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by Martin Honnen 4 months ago

Now tried to run the Linux Python multithreading stuff in gdb, log is

gdb) run Python3SimpleThreadingSaxonCHE112Ex1.py
Starting program: /usr/bin/python3 Python3SimpleThreadingSaxonCHE112Ex1.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff3e21700 (LWP 11271)]
[New Thread 0x7ffff3620700 (LWP 11272)]
[Thread 0x7ffff3620700 (LWP 11272) exited]
[New Thread 0x7ffff2e0b700 (LWP 11273)]
[New Thread 0x7ffff2bed700 (LWP 11274)]
[New Thread 0x7ffff298d700 (LWP 11275)]
[New Thread 0x7ffff296f700 (LWP 11276)]
[New Thread 0x7ffff2951700 (LWP 11277)]
[New Thread 0x7ffff2933700 (LWP 11278)]
[New Thread 0x7ffff2915700 (LWP 11279)]
[New Thread 0x7ffff28f7700 (LWP 11280)]
[New Thread 0x7ffff28d9700 (LWP 11281)]
[New Thread 0x7ffff28bb700 (LWP 11282)]
[New Thread 0x7ffff289d700 (LWP 11283)]
[New Thread 0x7ffff21dc700 (LWP 11284)]
[New Thread 0x7ffff20fa700 (LWP 11285)]
[New Thread 0x7ffff2018700 (LWP 11286)]
[New Thread 0x7ffff1dc3700 (LWP 11287)]
[New Thread 0x7ffff1ae1700 (LWP 11288)]
[New Thread 0x7ffff3620700 (LWP 11289)]
Starting Thread-1
[New Thread 0x7ffff17ff700 (LWP 11290)]
Starting Thread-2

Thread 20 "python3" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff3620700 (LWP 11289)]
0x00007ffff3e7fd49 in ?? () from /usr/lib/libsaxonhec.so

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by Martin Honnen 4 months ago

With the DEBUG flag enabled under Linux I get the following exception java.lang.StackOverflowError:

python3 Python3SimpleThreadingSaxonCHE112Ex1.py
SaxonProc constructor(l) called
SaxonProc constructor: jvm exists! jvmCreatedCPP=1
SaxonProc constructor(l) called
New processor created, Processor: 550045968
New processor created, Processor: 550045968
Starting Thread-1
Starting Thread-2
Exception in thread "main" java.lang.StackOverflowError

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by O'Neil Delpratt 4 months ago

Hi Martin,

Thank you for your posts. I will look carefully at your multithreading examples ASAP. Python web apps that work with multithreading is under tested.

Tips

  • Not to use Context manager (i.e. with) in multi-threaded applications as the release method may be called before a thread is done. This also applies to in Flask.

  • In Flask applications it is best to cache the PySaxonProcessor object so that it can be used throughout the application.

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by Martin Honnen 4 months ago

I have tried the multithreading code without with, it is

import threading
import time

from saxonc import *

exitFlag = 0

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter, xquery_processor):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
      self.xquery_processor = xquery_processor
   def run(self):
      print ("Starting " + self.name)
      example(self.name, self.counter, 5, self.xquery_processor)
      print ("Exiting " + self.name)

def example(threadName, delay, counter, xquery_processor):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print("%s : %s" % (threadName, xquery_processor.run_query_to_string(query_text = '"Hello from SaxonC: " || current-dateTime()')))
      counter -= 1


saxon_proc = PySaxonProcessor(license = False)

# Create new threads
thread1 = myThread(1, "Thread-1", 1, saxon_proc.new_xquery_processor())
thread2 = myThread(2, "Thread-2", 2, saxon_proc.new_xquery_processor())

# Start new Threads
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("Exiting Main Thread")

saxon_proc.release()

but (tested on Windows) fails with the same

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x0000000000a6730e
Please, contact the vendor of the application.
Crash dump will be written to "C:\Users\marti\source\repos\PythonMultiThreadingSaxonCHE112NoWithTest1\PythonMultiThreadingSaxonCHE112NoWithTest1\jet_dump_1504.dmp"

Exception 0xC0000005 (EXCEPTION_ACCESS_VIOLATION) at 0x0000000000a6730e (C:\Program Files\Saxonica\SaxonC HE 11.2\libsaxonhec.dll+0x66730e)
Failed to read memory at 0x000000a2b1240000

after calling each thread's method once:

Starting Thread-1
Starting Thread-2
Thread-1 : <?xml version="1.0" encoding="UTF-8"?>Hello from SaxonC: 2022-03-06T12:30:23.362+01:00
Thread-2 : <?xml version="1.0" encoding="UTF-8"?>Hello from SaxonC: 2022-03-06T12:30:24.339+01:00

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: system exception at 0x0000000000a6730e

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by O'Neil Delpratt 4 months ago

Thanks Martin for reporting this issue. I have reproduced it on my linux machine. Created the following bug issue to keep track of its progress: https://saxonica.plan.io/issues/5373

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by O'Neil Delpratt 4 months ago

Hi Martin,

The bug issue #5373 is now resolved, I have since turned my attention to running SaxonC on Flask. I am now getting a response with the simple example app you posted here: https://saxonica.plan.io/boards/4/topics/8523?r=8608#message-8608

After a few requests the server crashes as follows:

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: runtime error
Thread 33B13 ["Thread-1"] is terminated without notifying the JVM. Probably, "DetachCurrentThread" function was not called
Please, contact the vendor of the application.
Core dump will be piped to "/usr/share/apport/apport %p %s %c %d %P %E"
Extra information about error is saved in the "jet_err_211711.txt" file.

Aborted (core dumped)

I did expect this kind of error. I am wondering where we can add the call to detach_current_thread.

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by Martin Honnen 4 months ago

Hi,

thanks for looking into this. I am afraid I have no immediate idea on where/how to use your resolution of that multithreading bug and the addition of the detatch_current_thread to write a well working flask app, mainly because I don't know details as to when a request results in a new thread handling it or a request terminates a thread with flask, partly of course because I will probably need to run/test the API addition to understand its use reasonable well.

The general advice was also to make sure the PySaxonProcessor is stored/cached but even there I have not made progress as it seems so far that all kind of stores/caches the framework provides wants cacheable/storable objects to be kind of JSON serializable.

I am not sure how to proceed, if you want to release Saxon 11.3 perhaps it is better to leave this issue open and at least have a new release were basic multithreading using Saxon in Python works in a controlled way before looking for further improvements to find ways to control it inside of a more complex web application.

I will see whether I can write some test code over the weekend to get a better understanding of where/when Flask creates a new thread or terminates an existing one, will also look at the documentation whether it illuminates about the use of threads. Before that I don't have a good suggestion as to where to call detach_current_thread, I don't know whether I will have a good suggestion after doing some tests, we'll see.

RE: Need advice on how to use SaxonC 11.1 Python API in web application - Added by O'Neil Delpratt 4 months ago

I have resolved the issue of calling the detach_current_thread. I found this article helpful: https://flask.palletsprojects.com/en/2.0.x/appcontext/

In particular the details about teardown_X:

teardown_X() closes or otherwise deallocates the resource if it exists. It is registered as a teardown_appcontext() handler.

In the example I added the following:

@app.teardown_appcontext
def teardown_saxonc_thread(exception):
    proc.detach_current_thread

All requests now run without crashing.

(26-35/35)

Please register to reply