FreeOpcUa / python-opcua

LGPL Pure Python OPC-UA Client and Server
http://freeopcua.github.io/
GNU Lesser General Public License v3.0
1.32k stars 661 forks source link

Script hang upon exit when no stop() called #1473

Closed robgom closed 1 year ago

robgom commented 1 year ago

Describe the bug
When no stop() is called, one can't exit Python server application.

To Reproduce
The following code works fine (just a snippet of code similar to example server here):

    temperature_value = 20
    try:
        while True:  # temperature_value < 30:
            print("Temperature value: {}".format(temperature_value))
            temperature.set_value(temperature_value)

            temperature_value = temperature_value + 1
            if temperature_value > 30:
                temperature_value = 20
            time.sleep(1)
    finally:
        print("Stop server")
        server.stop()

But the following one does not:

    temperature_value = 20
    while True:  # temperature_value < 30:
        print("Temperature value: {}".format(temperature_value))
        temperature.set_value(temperature_value)

        temperature_value = temperature_value + 1
        if temperature_value > 30:
            temperature_value = 20
        time.sleep(1)

    print("Stop server")
    server.stop()

By "does not work" I mean when I launch the code and try to interrupt the script with ctrl-c, it hangs until I close the console window. While the former code version is present on your examples, I think the latter should also handle exiting gracefully.

Well, to be honest, I started this bug report with server in mind. However, client is also affected and exit() doesn't work properly:

>>> from opcua.client.client import Client
>>> c = Client("opc.tcp://127.0.0.1:4840")
>>> c.connect()
>>> exit()

After executing the following, console hangs until closing it forcibly.

Expected behavior
I would expect ctrl-c to be able to break script execution, even without stop being called.

Version
Python-Version: Python 3.9.10 win32 python-opcua Version (e.g. master branch, 0.9): opcua==0.98.13

swamper123 commented 1 year ago

Hey ho,

short hint:

The library is deprecated. Please switch to : opcua-asyncio which also has a sync-wrapper, with very few changes in API**

To your question: If you say that it works inside a try-except-finally Block, why don't you use this way (which is tbh. the best way to handle such things).

from time import sleep
try:
    while True:
        print("Do loop stuff")
        sleep(1)
except KeyboardInterrupt:
    print("Caught Keyboardinterrupt. Start KeyboardInterrupt cleanup tasks)
    # do some stuff
except:
    print("Caught some unexpected Exception or Error.")
finally:
    print("Start general Cleanup")
    # do cleanup things

I can't tell you where he is stuck in the code if ctrl-c happens, but it won't start cleaning up things.

About the Client stuff: I took a short view in the examples and each one has a try-except block around.

But I realy recommened that you to switch to the opcua-asyncio project in general

robgom commented 1 year ago

Thank you for the feedback. Will check what's recommended by you (async version).

Regarding my original version - I know try-finally to be the best pattern, but I also expect libraries to handle exiting gracefully. And when I experiment in my Python console, I don't write full Python code, it's most often one-liners. And it's hard to expect users to remember about a necessity to call stuff, instead of relying on exit() to do stuff. Would you agree to that?

oroulet commented 1 year ago

We start a thread. That is by design