Closed parthsharma1996 closed 5 years ago
Hi @parthsharma1996,
is WebMachine
initialized in a separate thread?
I am not sure if that is the case.
It's being used as a backend for a chatbot so the django-channels
does the initialization of the machine.
However, your commit https://github.com/aleneum/transitions-gui/commit/718a07af259c9fd0d3c684cde9f67670592aec68 seems to have fixed the issue since it works after I updated to the latest version
Hi, I have a somewhat similar issue and receive the error RuntimeError: There is no current event loop in thread 'Thread-4'.
I have implemented a simple statemachine that contains only automatic transitions after a timeout of 3 seconds. It runs in the terminal and shows the expected output. However, as soon as I open http://localhost:8080/?details=true
in the browser, it throws an exception and the browser GUI is not updated anymore.
Here is my minimum working example:
import sys
from os.path import join, realpath, dirname
import logging
from transitions.extensions.states import Timeout, Tags, add_state_features
from transitions_gui import WebMachine
sys.path.append(join(dirname(realpath(__file__)), '..'))
logging.basicConfig(level=logging.INFO)
@add_state_features(Timeout, Tags)
class CustomMachine(WebMachine):
pass
# Defines all states with entry and exit actions
states = [{'name': 'init', 'timeout': 3, 'on_timeout': 'move_to1'},
{'name': 'waypoint1', 'on_enter': 'moveJ1', 'on_exit': 'byebye_msg', 'timeout': 3, 'on_timeout': 'move_to2'},
{'name': 'waypoint2', 'on_enter': 'moveJ2', 'on_exit': 'byebye_msg', 'timeout': 3, 'on_timeout': 'move_to1'}]
# Defines all transitions with trigger, source and destination
transitions = [{'trigger': 'move_to1', 'source': ['init', 'waypoint2'], 'dest':'waypoint1'},
{'trigger': 'move_to2', 'source': 'waypoint1', 'dest':'waypoint2'}]
# Defines all actions called at entry or exit
class Actions(object):
def byebye_msg(self):
print('['+str(self.__class__.__name__)+'] Moving to next waypoint')
def moveJ1(self):
print('['+str(self.__class__.__name__)+'] Moving to waypoint 1')
def moveJ2(self):
print('['+str(self.__class__.__name__)+'] Moving to waypoint 2')
actions = Actions()
machine = CustomMachine(model=actions, states=states, transitions=transitions, initial='init',
name="Move to waypoints",
ignore_invalid_triggers=True,
auto_transitions=True)
# Automatic transition to first state (without this it did not start)
print(actions.state)
actions.move_to1()
Please note, that I had to manually trigger the first transition, i.e., on_timeout
in init
does not work properly.
And here is the error message that I am receiving after opening the GUI in the browser:
INFO:transitions_gui.web:Initializing tornado web application
INFO:transitions_gui.web:Starting server thread with daemon=False listening on port 8080
init
INFO:transitions.core:Move to waypoints: Finished processing state init exit callbacks.
[Actions] Moving to waypoint 1
INFO:transitions.core:Move to waypoints: Executed callback 'moveJ1'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint1 enter callbacks.
[Actions] Moving to next waypoint
INFO:transitions.core:Move to waypoints: Executed callback 'byebye_msg'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint1 exit callbacks.
[Actions] Moving to waypoint 2
INFO:transitions.core:Move to waypoints: Executed callback 'moveJ2'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint2 enter callbacks.
INFO:transitions.extensions.states:Move to waypoints: Timeout state waypoint1 processed.
[Actions] Moving to next waypoint
INFO:transitions.core:Move to waypoints: Executed callback 'byebye_msg'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint2 exit callbacks.
[Actions] Moving to waypoint 1
INFO:transitions.core:Move to waypoints: Executed callback 'moveJ1'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint1 enter callbacks.
INFO:transitions.extensions.states:Move to waypoints: Timeout state waypoint2 processed.
INFO:tornado.access:200 GET /?details=true (127.0.0.1) 1.53ms
INFO:tornado.access:200 GET /static/img/pencil.svg (127.0.0.1) 2.27ms
INFO:tornado.access:101 GET /ws (127.0.0.1) 0.79ms
INFO:transitions_gui.handlers:WebSocket opened
[Actions] Moving to next waypoint
INFO:transitions.core:Move to waypoints: Executed callback 'byebye_msg'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint1 exit callbacks.
[Actions] Moving to waypoint 2
INFO:transitions.core:Move to waypoints: Executed callback 'moveJ2'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint2 enter callbacks.
Exception in thread Thread-4:
Traceback (most recent call last):
File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
self.run()
File "/usr/lib/python3.8/threading.py", line 1254, in run
self.function(*self.args, **self.kwargs)
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions/extensions/states.py", line 114, in _process_timeout
event_data.machine.callback(callback, event_data)
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions/core.py", line 1144, in callback
func(*event_data.args, **event_data.kwargs)
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions/core.py", line 401, in trigger
return self.machine._process(func)
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions/core.py", line 1188, in _process
return trigger()
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions/core.py", line 426, in _trigger
return self._process(event_data)
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions/core.py", line 435, in _process
if trans.execute(event_data):
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions/core.py", line 276, in execute
self._change_state(event_data)
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions_gui/web.py", line 20, in _change_state
event_data.machine.websocket_handler.send_message({"method": "state_changed",
File "/home/mmaier/.local/lib/python3.8/site-packages/transitions_gui/handlers/__init__.py", line 25, in send_message
s.write_message(message, binary=False)
File "/home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py", line 340, in write_message
return self.ws_connection.write_message(message, binary=binary)
File "/home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py", line 1096, in write_message
fut = self._write_frame(True, opcode, message, flags=flags)
File "/home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py", line 1073, in _write_frame
return self.stream.write(frame)
File "/home/mmaier/.local/lib/python3.8/site-packages/tornado/iostream.py", line 540, in write
future = Future() # type: Future[None]
File "/usr/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-4'.
[Actions] Moving to next waypoint
INFO:transitions.core:Move to waypoints: Executed callback 'byebye_msg'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint2 exit callbacks.
[Actions] Moving to waypoint 1
INFO:transitions.core:Move to waypoints: Executed callback 'moveJ1'
INFO:transitions.core:Move to waypoints: Finished processing state waypoint1 enter callbacks.
Exception in thread Thread-5:
Traceback (most recent call last):
Obviously, the statemachine keeps running, but the exception is thrown everytime the timeout is exceeded and the GUI doesn't show any updates. As soon as I close the browser window, there are no more exceptions and the statemachine keeps on running.
UPDATE:
I've fixed this similar to the exception mentioned above, by adding an exception handler and creating a new event loop in web.py
like this:
try:
event_data.machine.websocket_handler.send_message({"method": "state_changed",
"arg": {"model": model_name, "transition": transition,
"state": current_state}})
except RuntimeError:
import asyncio
asyncio.set_event_loop(asyncio.new_event_loop())
event_data.machine.websocket_handler.send_message({"method": "state_changed",
"arg": {"model": model_name, "transition": transition,
"state": current_state}})
except ImportError:
_LOGGER.warn("Could not initialize event loop correctly.")
Now, the statemachine runs and the browser GUI is updated properly. However, I am receiving the following error from time to time:
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-7' coro=<WebSocketProtocol13.write_message.<locals>.wrapper() running at /home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py:1100>>
/usr/lib/python3.8/asyncio/base_events.py:641: RuntimeWarning: coroutine 'WebSocketProtocol13.write_message.<locals>.wrapper' was never awaited
self._ready.clear()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-8' coro=<WebSocketProtocol13.write_message.<locals>.wrapper() running at /home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py:1100>>
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-9' coro=<WebSocketProtocol13.write_message.<locals>.wrapper() running at /home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py:1100>>
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-10' coro=<WebSocketProtocol13.write_message.<locals>.wrapper() running at /home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py:1100>>
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-11' coro=<WebSocketProtocol13.write_message.<locals>.wrapper() running at /home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py:1100>>
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-12' coro=<WebSocketProtocol13.write_message.<locals>.wrapper() running at /home/mmaier/.local/lib/python3.8/site-packages/tornado/websocket.py:1100>>
Note that statemachine and browser GUI keep running, even if this error pops up. For now, I can live with that, but am curious if this can be fixed as well!
WTF, having same issue...
I tried running this with my current modification of the transitions ( see this and this)
I am receiving the following error while trying to do that. Can you give me pointers as to where it might be going wrong?
Normally I would spend some time trying to figure out the error on my own, but in this case I am bit lost since I don't have a lot of experience with threads and aync functions in general.