Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client can't get notification until method complete #1488

Open
frinklai opened this issue Oct 3, 2022 · 10 comments
Open

Client can't get notification until method complete #1488

frinklai opened this issue Oct 3, 2022 · 10 comments

Comments

@frinklai
Copy link

frinklai commented Oct 3, 2022

Describe the bug

[What I do]

  1. Create an UA server with a method that can trigger an event

  2. Create UA clientA which register the event.

  3. Create clientB and use it to trigger event by call ua method.

[ISSUE]

  • I found when I use another ua clientB to call UA_method_for_trigger_event, the event_notification in clientA will executed until UA_method_for_trigger_event complete.

  • Is there any way to let client get notification immediately, while event_generator trigger signal

[Simple example code are as follows:]

[server.py]

    def UA_method_for_trigger_event():   # <====== Suppose this is an UA method in UA server.
        event_generator.trigger(message="")
        time.sleep(30)

[clientA.py]

    class UASubscriber(object):
        def __init__(self):
           pass 

        def event_notification(self, event):
            # Will execute until  'UA_method_for_trigger_event ' in server complete   <====== ISSUE
            data = event.get_event_props_as_fields_dict()
            print("data = ", data)

Expected behavior

Is there any way to let client get notification while event_generator.trigger event_generator.trigger singal

Version

python 3.8

@frinklai
Copy link
Author

frinklai commented Oct 3, 2022

BTW
I just found the problem is the if condition in below code is not true,
but I still have no idea about why and how to solve it

internal_subscription.py - _pop_triggered_events

@oroulet
Copy link
Member

oroulet commented Oct 3, 2022

not sure either but you should really use asyncua and not python-opcua...

@AndreasHeine
Copy link
Member

ua-methods aren't supposed to have long execution times like more then a few seconds for those usecases opc ua has defined "Part 10 Programs" https://reference.opcfoundation.org/Core/Part10/4.1/

.trigger() just creates and appends a event-notification to the queue which will be emptied in the next publishinterval

@oroulet
Copy link
Member

oroulet commented Oct 3, 2022

But it is strange that that call hangs the processing of events. Even if such a long call should not be done.
If asyncua has the same issue might need to have a look

@AndreasHeine
Copy link
Member

if you follow the trigger method you will end up in internal subscription append to queue... from first view there cant hang anything ^^

self.isession.subscription_service.trigger_event(self.event)

def _trigger_event(self, event, mid):

@oroulet
Copy link
Member

oroulet commented Oct 3, 2022

Might be the same thread doing both things. You cannot have so many threads in python. I think i fixed/improved something like that in asyncua once

@AndreasHeine
Copy link
Member

@oroulet
image

from the data it looks correct but with ua expert i can confirm that it shows the event after the call is done!?

Publish interval of the Event subscription is at 500ms so a lot faster then the 5s sleep!

Testcode:

import asyncio
import logging
from asyncua import ua
from asyncua.server import Server, EventGenerator
import datetime

# logging.basicConfig(level=logging.INFO)
# _logger = logging.getLogger('asyncua')

async def main():
    server = Server()
    await server.init()
    server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    idx = await server.register_namespace(uri)
    # populating our address space
    myobj = await server.nodes.objects.add_object(idx, "MyObject")

    myevgen = await server.get_event_generator(ua.ObjectIds.BaseEventType, myobj)

    async def func(parent, variant):
        print("Calltimestamp", datetime.datetime.now())
        myevgen.event.Message = ua.LocalizedText("MyFirstEvent %d" % variant.Value)
        myevgen.event.Severity = 500
        await myevgen.trigger()
        await asyncio.sleep(5)
        print("Donetimestamp", datetime.datetime.now())
        ret = False
        if variant.Value % 2 == 0:
            ret = True
        return [ua.Variant(ret, ua.VariantType.Boolean)]

    await myobj.add_method(idx, "mymethod", func, [ua.VariantType.Int64], [ua.VariantType.Boolean])

    async with server:
        while True:
            await asyncio.sleep(1)


if __name__ == "__main__":
    asyncio.run(main())

@frinklai
Copy link
Author

frinklai commented Oct 4, 2022

@AndreasHeine @oroulet
Got it, thanks very much for your test code and suggestions, I will try to using async opcua in my project.

@AndreasHeine
Copy link
Member

@frinklai the timestamps are looking correct can you tell me what clientA (the subscribing one) is? UaExpert or a different tool / software?

just to make sure its not just uaexpert making some sync thread stuff with the ui...

@frinklai
Copy link
Author

frinklai commented Oct 5, 2022

@AndreasHeine Both client A and client B are a python script.
I think maybe I need to use async opcua, rather than python-opcua, so that event can trigger immediately.
Is that right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants